Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Dieser Commit ist enthalten in:
108
drivers/s390/net/Kconfig
Normale Datei
108
drivers/s390/net/Kconfig
Normale Datei
@@ -0,0 +1,108 @@
|
||||
menu "S/390 network device drivers"
|
||||
depends on NETDEVICES && ARCH_S390
|
||||
|
||||
config LCS
|
||||
tristate "Lan Channel Station Interface"
|
||||
depends on NETDEVICES && (NET_ETHERNET || TR || FDDI)
|
||||
help
|
||||
Select this option if you want to use LCS networking on IBM S/390
|
||||
or zSeries. This device driver supports Token Ring (IEEE 802.5),
|
||||
FDDI (IEEE 802.7) and Ethernet.
|
||||
This option is also available as a module which will be
|
||||
called lcs.ko. If you do not know what it is, it's safe to say "Y".
|
||||
|
||||
config CTC
|
||||
tristate "CTC device support"
|
||||
depends on NETDEVICES
|
||||
help
|
||||
Select this option if you want to use channel-to-channel networking
|
||||
on IBM S/390 or zSeries. This device driver supports real CTC
|
||||
coupling using ESCON. It also supports virtual CTCs when running
|
||||
under VM. It will use the channel device configuration if this is
|
||||
available. This option is also available as a module which will be
|
||||
called ctc.ko. If you do not know what it is, it's safe to say "Y".
|
||||
|
||||
config IUCV
|
||||
tristate "IUCV support (VM only)"
|
||||
help
|
||||
Select this option if you want to use inter-user communication
|
||||
under VM or VIF. If unsure, say "Y" to enable a fast communication
|
||||
link between VM guests. At boot time the user ID of the guest needs
|
||||
to be passed to the kernel. Note that both kernels need to be
|
||||
compiled with this option and both need to be booted with the user ID
|
||||
of the other VM guest.
|
||||
|
||||
config NETIUCV
|
||||
tristate "IUCV network device support (VM only)"
|
||||
depends on IUCV && NETDEVICES
|
||||
help
|
||||
Select this option if you want to use inter-user communication
|
||||
vehicle networking under VM or VIF. It enables a fast communication
|
||||
link between VM guests. Using ifconfig a point-to-point connection
|
||||
can be established to the Linux for zSeries and S7390 system
|
||||
running on the other VM guest. This option is also available
|
||||
as a module which will be called netiucv.ko. If unsure, say "Y".
|
||||
|
||||
config SMSGIUCV
|
||||
tristate "IUCV special message support (VM only)"
|
||||
depends on IUCV
|
||||
help
|
||||
Select this option if you want to be able to receive SMSG messages
|
||||
from other VM guest systems.
|
||||
|
||||
config CLAW
|
||||
tristate "CLAW device support"
|
||||
depends on NETDEVICES
|
||||
help
|
||||
This driver supports channel attached CLAW devices.
|
||||
CLAW is Common Link Access for Workstation. Common devices
|
||||
that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices.
|
||||
To compile as a module choose M here: The module will be called
|
||||
claw.ko to compile into the kernel choose Y
|
||||
|
||||
config QETH
|
||||
tristate "Gigabit Ethernet device support"
|
||||
depends on NETDEVICES && IP_MULTICAST && QDIO
|
||||
help
|
||||
This driver supports the IBM S/390 and zSeries OSA Express adapters
|
||||
in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN
|
||||
interfaces in QDIO and HIPER mode.
|
||||
|
||||
For details please refer to the documentation provided by IBM at
|
||||
<http://www10.software.ibm.com/developerworks/opensource/linux390>
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called qeth.ko.
|
||||
|
||||
|
||||
comment "Gigabit Ethernet default settings"
|
||||
depends on QETH
|
||||
|
||||
config QETH_IPV6
|
||||
bool "IPv6 support for gigabit ethernet"
|
||||
depends on (QETH = IPV6) || (QETH && IPV6 = 'y')
|
||||
help
|
||||
If CONFIG_QETH is switched on, this option will include IPv6
|
||||
support in the qeth device driver.
|
||||
|
||||
config QETH_VLAN
|
||||
bool "VLAN support for gigabit ethernet"
|
||||
depends on (QETH = VLAN_8021Q) || (QETH && VLAN_8021Q = 'y')
|
||||
help
|
||||
If CONFIG_QETH is switched on, this option will include IEEE
|
||||
802.1q VLAN support in the qeth device driver.
|
||||
|
||||
config QETH_PERF_STATS
|
||||
bool "Performance statistics in /proc"
|
||||
depends on QETH
|
||||
help
|
||||
When switched on, this option will add a file in the proc-fs
|
||||
(/proc/qeth_perf_stats) containing performance statistics. It
|
||||
may slightly impact performance, so this is only recommended for
|
||||
internal tuning of the device driver.
|
||||
|
||||
config CCWGROUP
|
||||
tristate
|
||||
default (LCS || CTC || QETH)
|
||||
|
||||
endmenu
|
14
drivers/s390/net/Makefile
Normale Datei
14
drivers/s390/net/Makefile
Normale Datei
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# S/390 network devices
|
||||
#
|
||||
|
||||
ctc-objs := ctcmain.o ctctty.o ctcdbug.o
|
||||
|
||||
obj-$(CONFIG_IUCV) += iucv.o
|
||||
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
|
||||
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
|
||||
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
|
||||
obj-$(CONFIG_LCS) += lcs.o cu3088.o
|
||||
qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o
|
||||
qeth-$(CONFIG_PROC_FS) += qeth_proc.o
|
||||
obj-$(CONFIG_QETH) += qeth.o
|
4447
drivers/s390/net/claw.c
Normale Datei
4447
drivers/s390/net/claw.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
335
drivers/s390/net/claw.h
Normale Datei
335
drivers/s390/net/claw.h
Normale Datei
@@ -0,0 +1,335 @@
|
||||
/*******************************************************
|
||||
* Define constants *
|
||||
* *
|
||||
********************************************************/
|
||||
#define VERSION_CLAW_H "$Revision: 1.6 $"
|
||||
/*-----------------------------------------------------*
|
||||
* CCW command codes for CLAW protocol *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
#define CCW_CLAW_CMD_WRITE 0x01 /* write - not including link */
|
||||
#define CCW_CLAW_CMD_READ 0x02 /* read */
|
||||
#define CCW_CLAW_CMD_NOP 0x03 /* NOP */
|
||||
#define CCW_CLAW_CMD_SENSE 0x04 /* Sense */
|
||||
#define CCW_CLAW_CMD_SIGNAL_SMOD 0x05 /* Signal Status Modifier */
|
||||
#define CCW_CLAW_CMD_TIC 0x08 /* TIC */
|
||||
#define CCW_CLAW_CMD_READHEADER 0x12 /* read header data */
|
||||
#define CCW_CLAW_CMD_READFF 0x22 /* read an FF */
|
||||
#define CCW_CLAW_CMD_SENSEID 0xe4 /* Sense ID */
|
||||
|
||||
|
||||
/*-----------------------------------------------------*
|
||||
* CLAW Unique constants *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
#define MORE_to_COME_FLAG 0x04 /* OR with write CCW in case of m-t-c */
|
||||
#define CLAW_IDLE 0x00 /* flag to indicate CLAW is idle */
|
||||
#define CLAW_BUSY 0xff /* flag to indicate CLAW is busy */
|
||||
#define CLAW_PENDING 0x00 /* flag to indicate i/o is pending */
|
||||
#define CLAW_COMPLETE 0xff /* flag to indicate i/o completed */
|
||||
|
||||
/*-----------------------------------------------------*
|
||||
* CLAW control comand code *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
#define SYSTEM_VALIDATE_REQUEST 0x01 /* System Validate request */
|
||||
#define SYSTEM_VALIDATE_RESPONSE 0x02 /* System Validate response */
|
||||
#define CONNECTION_REQUEST 0x21 /* Connection request */
|
||||
#define CONNECTION_RESPONSE 0x22 /* Connection response */
|
||||
#define CONNECTION_CONFIRM 0x23 /* Connection confirm */
|
||||
#define DISCONNECT 0x24 /* Disconnect */
|
||||
#define CLAW_ERROR 0x41 /* CLAW error message */
|
||||
#define CLAW_VERSION_ID 2 /* CLAW version ID */
|
||||
|
||||
/*-----------------------------------------------------*
|
||||
* CLAW adater sense bytes *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
#define CLAW_ADAPTER_SENSE_BYTE 0x41 /* Stop command issued to adapter */
|
||||
|
||||
/*-----------------------------------------------------*
|
||||
* CLAW control command return codes *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
#define CLAW_RC_NAME_MISMATCH 166 /* names do not match */
|
||||
#define CLAW_RC_WRONG_VERSION 167 /* wrong CLAW version number */
|
||||
#define CLAW_RC_HOST_RCV_TOO_SMALL 180 /* Host maximum receive is */
|
||||
/* less than Linux on zSeries*/
|
||||
/* transmit size */
|
||||
|
||||
/*-----------------------------------------------------*
|
||||
* CLAW Constants application name *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
#define HOST_APPL_NAME "TCPIP "
|
||||
#define WS_APPL_NAME_IP_LINK "TCPIP "
|
||||
#define WS_APPL_NAME_IP_NAME "IP "
|
||||
#define WS_APPL_NAME_API_LINK "API "
|
||||
#define WS_APPL_NAME_PACKED "PACKED "
|
||||
#define WS_NAME_NOT_DEF "NOT_DEF "
|
||||
#define PACKING_ASK 1
|
||||
#define PACK_SEND 2
|
||||
#define DO_PACKED 3
|
||||
|
||||
#define MAX_ENVELOPE_SIZE 65536
|
||||
#define CLAW_DEFAULT_MTU_SIZE 4096
|
||||
#define DEF_PACK_BUFSIZE 32768
|
||||
#define READ 0
|
||||
#define WRITE 1
|
||||
|
||||
#define TB_TX 0 /* sk buffer handling in process */
|
||||
#define TB_STOP 1 /* network device stop in process */
|
||||
#define TB_RETRY 2 /* retry in process */
|
||||
#define TB_NOBUFFER 3 /* no buffer on free queue */
|
||||
#define CLAW_MAX_LINK_ID 1
|
||||
#define CLAW_MAX_DEV 256 /* max claw devices */
|
||||
#define MAX_NAME_LEN 8 /* host name, adapter name length */
|
||||
#define CLAW_FRAME_SIZE 4096
|
||||
#define CLAW_ID_SIZE BUS_ID_SIZE+3
|
||||
|
||||
/* state machine codes used in claw_irq_handler */
|
||||
|
||||
#define CLAW_STOP 0
|
||||
#define CLAW_START_HALT_IO 1
|
||||
#define CLAW_START_SENSEID 2
|
||||
#define CLAW_START_READ 3
|
||||
#define CLAW_START_WRITE 4
|
||||
|
||||
/*-----------------------------------------------------*
|
||||
* Lock flag *
|
||||
*------------------------------------------------------*/
|
||||
#define LOCK_YES 0
|
||||
#define LOCK_NO 1
|
||||
|
||||
/*-----------------------------------------------------*
|
||||
* DBF Debug macros *
|
||||
*------------------------------------------------------*/
|
||||
#define CLAW_DBF_TEXT(level, name, text) \
|
||||
do { \
|
||||
debug_text_event(claw_dbf_##name, level, text); \
|
||||
} while (0)
|
||||
|
||||
#define CLAW_DBF_HEX(level,name,addr,len) \
|
||||
do { \
|
||||
debug_event(claw_dbf_##name,level,(void*)(addr),len); \
|
||||
} while (0)
|
||||
|
||||
#define CLAW_DBF_TEXT_(level,name,text...) \
|
||||
do { \
|
||||
sprintf(debug_buffer, text); \
|
||||
debug_text_event(claw_dbf_##name,level, debug_buffer);\
|
||||
} while (0)
|
||||
|
||||
/*******************************************************
|
||||
* Define Control Blocks *
|
||||
* *
|
||||
********************************************************/
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* CLAW header */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct clawh {
|
||||
__u16 length; /* length of data read by preceding read CCW */
|
||||
__u8 opcode; /* equivalent read CCW */
|
||||
__u8 flag; /* flag of FF to indicate read was completed */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* CLAW Packing header 4 bytes */
|
||||
/*------------------------------------------------------*/
|
||||
struct clawph {
|
||||
__u16 len; /* Length of Packed Data Area */
|
||||
__u8 flag; /* Reserved not used */
|
||||
__u8 link_num; /* Link ID */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* CLAW Ending struct ccwbk */
|
||||
/*------------------------------------------------------*/
|
||||
struct endccw {
|
||||
__u32 real; /* real address of this block */
|
||||
__u8 write1; /* write 1 is active */
|
||||
__u8 read1; /* read 1 is active */
|
||||
__u16 reserved; /* reserved for future use */
|
||||
struct ccw1 write1_nop1;
|
||||
struct ccw1 write1_nop2;
|
||||
struct ccw1 write2_nop1;
|
||||
struct ccw1 write2_nop2;
|
||||
struct ccw1 read1_nop1;
|
||||
struct ccw1 read1_nop2;
|
||||
struct ccw1 read2_nop1;
|
||||
struct ccw1 read2_nop2;
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* CLAW struct ccwbk */
|
||||
/*------------------------------------------------------*/
|
||||
struct ccwbk {
|
||||
void *next; /* pointer to next ccw block */
|
||||
__u32 real; /* real address of this ccw */
|
||||
void *p_buffer; /* virtual address of data */
|
||||
struct clawh header; /* claw header */
|
||||
struct ccw1 write; /* write CCW */
|
||||
struct ccw1 w_read_FF; /* read FF */
|
||||
struct ccw1 w_TIC_1; /* TIC */
|
||||
struct ccw1 read; /* read CCW */
|
||||
struct ccw1 read_h; /* read header */
|
||||
struct ccw1 signal; /* signal SMOD */
|
||||
struct ccw1 r_TIC_1; /* TIC1 */
|
||||
struct ccw1 r_read_FF; /* read FF */
|
||||
struct ccw1 r_TIC_2; /* TIC2 */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* CLAW control block */
|
||||
/*------------------------------------------------------*/
|
||||
struct clawctl {
|
||||
__u8 command; /* control command */
|
||||
__u8 version; /* CLAW protocol version */
|
||||
__u8 linkid; /* link ID */
|
||||
__u8 correlator; /* correlator */
|
||||
__u8 rc; /* return code */
|
||||
__u8 reserved1; /* reserved */
|
||||
__u8 reserved2; /* reserved */
|
||||
__u8 reserved3; /* reserved */
|
||||
__u8 data[24]; /* command specific fields */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Data for SYSTEMVALIDATE command */
|
||||
/*------------------------------------------------------*/
|
||||
struct sysval {
|
||||
char WS_name[8]; /* Workstation System name */
|
||||
char host_name[8]; /* Host system name */
|
||||
__u16 read_frame_size; /* read frame size */
|
||||
__u16 write_frame_size; /* write frame size */
|
||||
__u8 reserved[4]; /* reserved */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Data for Connect command */
|
||||
/*------------------------------------------------------*/
|
||||
struct conncmd {
|
||||
char WS_name[8]; /* Workstation application name */
|
||||
char host_name[8]; /* Host application name */
|
||||
__u16 reserved1[2]; /* read frame size */
|
||||
__u8 reserved2[4]; /* reserved */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Data for CLAW error */
|
||||
/*------------------------------------------------------*/
|
||||
struct clawwerror {
|
||||
char reserved1[8]; /* reserved */
|
||||
char reserved2[8]; /* reserved */
|
||||
char reserved3[8]; /* reserved */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Data buffer for CLAW */
|
||||
/*------------------------------------------------------*/
|
||||
struct clawbuf {
|
||||
char buffer[MAX_ENVELOPE_SIZE]; /* data buffer */
|
||||
};
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* Channel control block for read and write channel */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
struct chbk {
|
||||
unsigned int devno;
|
||||
int irq;
|
||||
char id[CLAW_ID_SIZE];
|
||||
__u32 IO_active;
|
||||
__u8 claw_state;
|
||||
struct irb *irb;
|
||||
struct ccw_device *cdev; /* pointer to the channel device */
|
||||
struct net_device *ndev;
|
||||
wait_queue_head_t wait;
|
||||
struct tasklet_struct tasklet;
|
||||
struct timer_list timer;
|
||||
unsigned long flag_a; /* atomic flags */
|
||||
#define CLAW_BH_ACTIVE 0
|
||||
unsigned long flag_b; /* atomic flags */
|
||||
#define CLAW_WRITE_ACTIVE 0
|
||||
__u8 last_dstat;
|
||||
__u8 flag;
|
||||
struct sk_buff_head collect_queue;
|
||||
spinlock_t collect_lock;
|
||||
#define CLAW_WRITE 0x02 /* - Set if this is a write channel */
|
||||
#define CLAW_READ 0x01 /* - Set if this is a read channel */
|
||||
#define CLAW_TIMER 0x80 /* - Set if timer made the wake_up */
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------*
|
||||
* CLAW environment block *
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
struct claw_env {
|
||||
unsigned int devno[2]; /* device number */
|
||||
char host_name[9]; /* Host name */
|
||||
char adapter_name [9]; /* adapter name */
|
||||
char api_type[9]; /* TCPIP, API or PACKED */
|
||||
void *p_priv; /* privptr */
|
||||
__u16 read_buffers; /* read buffer number */
|
||||
__u16 write_buffers; /* write buffer number */
|
||||
__u16 read_size; /* read buffer size */
|
||||
__u16 write_size; /* write buffer size */
|
||||
__u16 dev_id; /* device ident */
|
||||
__u8 packing; /* are we packing? */
|
||||
volatile __u8 queme_switch; /* gate for imed packing */
|
||||
volatile unsigned long pk_delay; /* Delay for adaptive packing */
|
||||
__u8 in_use; /* device active flag */
|
||||
struct net_device *ndev; /* backward ptr to the net dev*/
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------*
|
||||
* CLAW main control block *
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
struct claw_privbk {
|
||||
void *p_buff_ccw;
|
||||
__u32 p_buff_ccw_num;
|
||||
void *p_buff_read;
|
||||
__u32 p_buff_read_num;
|
||||
__u32 p_buff_pages_perread;
|
||||
void *p_buff_write;
|
||||
__u32 p_buff_write_num;
|
||||
__u32 p_buff_pages_perwrite;
|
||||
long active_link_ID; /* Active logical link ID */
|
||||
struct ccwbk *p_write_free_chain; /* pointer to free ccw chain */
|
||||
struct ccwbk *p_write_active_first; /* ptr to the first write ccw */
|
||||
struct ccwbk *p_write_active_last; /* ptr to the last write ccw */
|
||||
struct ccwbk *p_read_active_first; /* ptr to the first read ccw */
|
||||
struct ccwbk *p_read_active_last; /* ptr to the last read ccw */
|
||||
struct endccw *p_end_ccw; /*ptr to ending ccw */
|
||||
struct ccwbk *p_claw_signal_blk; /* ptr to signal block */
|
||||
__u32 write_free_count; /* number of free bufs for write */
|
||||
struct net_device_stats stats; /* device status */
|
||||
struct chbk channel[2]; /* Channel control blocks */
|
||||
__u8 mtc_skipping;
|
||||
int mtc_offset;
|
||||
int mtc_logical_link;
|
||||
void *p_mtc_envelope;
|
||||
struct sk_buff *pk_skb; /* packing buffer */
|
||||
int pk_cnt;
|
||||
struct clawctl ctl_bk;
|
||||
struct claw_env *p_env;
|
||||
__u8 system_validate_comp;
|
||||
__u8 release_pend;
|
||||
__u8 checksum_received_ip_pkts;
|
||||
__u8 buffs_alloc;
|
||||
struct endccw end_ccw;
|
||||
unsigned long tbusy;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/* define global constants */
|
||||
/************************************************************/
|
||||
|
||||
#define CCWBK_SIZE sizeof(struct ccwbk)
|
||||
|
||||
|
83
drivers/s390/net/ctcdbug.c
Normale Datei
83
drivers/s390/net/ctcdbug.c
Normale Datei
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
*
|
||||
* linux/drivers/s390/net/ctcdbug.c ($Revision: 1.4 $)
|
||||
*
|
||||
* CTC / ESCON network driver - s390 dbf exploit.
|
||||
*
|
||||
* Copyright 2000,2003 IBM Corporation
|
||||
*
|
||||
* Author(s): Original Code written by
|
||||
* Peter Tiedemann (ptiedem@de.ibm.com)
|
||||
*
|
||||
* $Revision: 1.4 $ $Date: 2004/08/04 10:11:59 $
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ctcdbug.h"
|
||||
|
||||
/**
|
||||
* Debug Facility Stuff
|
||||
*/
|
||||
debug_info_t *ctc_dbf_setup = NULL;
|
||||
debug_info_t *ctc_dbf_data = NULL;
|
||||
debug_info_t *ctc_dbf_trace = NULL;
|
||||
|
||||
DEFINE_PER_CPU(char[256], ctc_dbf_txt_buf);
|
||||
|
||||
void
|
||||
ctc_unregister_dbf_views(void)
|
||||
{
|
||||
if (ctc_dbf_setup)
|
||||
debug_unregister(ctc_dbf_setup);
|
||||
if (ctc_dbf_data)
|
||||
debug_unregister(ctc_dbf_data);
|
||||
if (ctc_dbf_trace)
|
||||
debug_unregister(ctc_dbf_trace);
|
||||
}
|
||||
int
|
||||
ctc_register_dbf_views(void)
|
||||
{
|
||||
ctc_dbf_setup = debug_register(CTC_DBF_SETUP_NAME,
|
||||
CTC_DBF_SETUP_INDEX,
|
||||
CTC_DBF_SETUP_NR_AREAS,
|
||||
CTC_DBF_SETUP_LEN);
|
||||
ctc_dbf_data = debug_register(CTC_DBF_DATA_NAME,
|
||||
CTC_DBF_DATA_INDEX,
|
||||
CTC_DBF_DATA_NR_AREAS,
|
||||
CTC_DBF_DATA_LEN);
|
||||
ctc_dbf_trace = debug_register(CTC_DBF_TRACE_NAME,
|
||||
CTC_DBF_TRACE_INDEX,
|
||||
CTC_DBF_TRACE_NR_AREAS,
|
||||
CTC_DBF_TRACE_LEN);
|
||||
|
||||
if ((ctc_dbf_setup == NULL) || (ctc_dbf_data == NULL) ||
|
||||
(ctc_dbf_trace == NULL)) {
|
||||
ctc_unregister_dbf_views();
|
||||
return -ENOMEM;
|
||||
}
|
||||
debug_register_view(ctc_dbf_setup, &debug_hex_ascii_view);
|
||||
debug_set_level(ctc_dbf_setup, CTC_DBF_SETUP_LEVEL);
|
||||
|
||||
debug_register_view(ctc_dbf_data, &debug_hex_ascii_view);
|
||||
debug_set_level(ctc_dbf_data, CTC_DBF_DATA_LEVEL);
|
||||
|
||||
debug_register_view(ctc_dbf_trace, &debug_hex_ascii_view);
|
||||
debug_set_level(ctc_dbf_trace, CTC_DBF_TRACE_LEVEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
123
drivers/s390/net/ctcdbug.h
Normale Datei
123
drivers/s390/net/ctcdbug.h
Normale Datei
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
*
|
||||
* linux/drivers/s390/net/ctcdbug.h ($Revision: 1.4 $)
|
||||
*
|
||||
* CTC / ESCON network driver - s390 dbf exploit.
|
||||
*
|
||||
* Copyright 2000,2003 IBM Corporation
|
||||
*
|
||||
* Author(s): Original Code written by
|
||||
* Peter Tiedemann (ptiedem@de.ibm.com)
|
||||
*
|
||||
* $Revision: 1.4 $ $Date: 2004/10/15 09:26:58 $
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/debug.h>
|
||||
/**
|
||||
* Debug Facility stuff
|
||||
*/
|
||||
#define CTC_DBF_SETUP_NAME "ctc_setup"
|
||||
#define CTC_DBF_SETUP_LEN 16
|
||||
#define CTC_DBF_SETUP_INDEX 3
|
||||
#define CTC_DBF_SETUP_NR_AREAS 1
|
||||
#define CTC_DBF_SETUP_LEVEL 3
|
||||
|
||||
#define CTC_DBF_DATA_NAME "ctc_data"
|
||||
#define CTC_DBF_DATA_LEN 128
|
||||
#define CTC_DBF_DATA_INDEX 3
|
||||
#define CTC_DBF_DATA_NR_AREAS 1
|
||||
#define CTC_DBF_DATA_LEVEL 2
|
||||
|
||||
#define CTC_DBF_TRACE_NAME "ctc_trace"
|
||||
#define CTC_DBF_TRACE_LEN 16
|
||||
#define CTC_DBF_TRACE_INDEX 2
|
||||
#define CTC_DBF_TRACE_NR_AREAS 2
|
||||
#define CTC_DBF_TRACE_LEVEL 3
|
||||
|
||||
#define DBF_TEXT(name,level,text) \
|
||||
do { \
|
||||
debug_text_event(ctc_dbf_##name,level,text); \
|
||||
} while (0)
|
||||
|
||||
#define DBF_HEX(name,level,addr,len) \
|
||||
do { \
|
||||
debug_event(ctc_dbf_##name,level,(void*)(addr),len); \
|
||||
} while (0)
|
||||
|
||||
DECLARE_PER_CPU(char[256], ctc_dbf_txt_buf);
|
||||
extern debug_info_t *ctc_dbf_setup;
|
||||
extern debug_info_t *ctc_dbf_data;
|
||||
extern debug_info_t *ctc_dbf_trace;
|
||||
|
||||
|
||||
#define DBF_TEXT_(name,level,text...) \
|
||||
do { \
|
||||
char* ctc_dbf_txt_buf = get_cpu_var(ctc_dbf_txt_buf); \
|
||||
sprintf(ctc_dbf_txt_buf, text); \
|
||||
debug_text_event(ctc_dbf_##name,level,ctc_dbf_txt_buf); \
|
||||
put_cpu_var(ctc_dbf_txt_buf); \
|
||||
} while (0)
|
||||
|
||||
#define DBF_SPRINTF(name,level,text...) \
|
||||
do { \
|
||||
debug_sprintf_event(ctc_dbf_trace, level, ##text ); \
|
||||
debug_sprintf_event(ctc_dbf_trace, level, text ); \
|
||||
} while (0)
|
||||
|
||||
|
||||
int ctc_register_dbf_views(void);
|
||||
|
||||
void ctc_unregister_dbf_views(void);
|
||||
|
||||
/**
|
||||
* some more debug stuff
|
||||
*/
|
||||
|
||||
#define HEXDUMP16(importance,header,ptr) \
|
||||
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
|
||||
*(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
|
||||
*(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
|
||||
*(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
|
||||
*(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
|
||||
*(((char*)ptr)+12),*(((char*)ptr)+13), \
|
||||
*(((char*)ptr)+14),*(((char*)ptr)+15)); \
|
||||
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
|
||||
*(((char*)ptr)+16),*(((char*)ptr)+17), \
|
||||
*(((char*)ptr)+18),*(((char*)ptr)+19), \
|
||||
*(((char*)ptr)+20),*(((char*)ptr)+21), \
|
||||
*(((char*)ptr)+22),*(((char*)ptr)+23), \
|
||||
*(((char*)ptr)+24),*(((char*)ptr)+25), \
|
||||
*(((char*)ptr)+26),*(((char*)ptr)+27), \
|
||||
*(((char*)ptr)+28),*(((char*)ptr)+29), \
|
||||
*(((char*)ptr)+30),*(((char*)ptr)+31));
|
||||
|
||||
static inline void
|
||||
hex_dump(unsigned char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i && !(i % 16))
|
||||
printk("\n");
|
||||
printk("%02x ", *(buf + i));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
3304
drivers/s390/net/ctcmain.c
Normale Datei
3304
drivers/s390/net/ctcmain.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
1276
drivers/s390/net/ctctty.c
Normale Datei
1276
drivers/s390/net/ctctty.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
37
drivers/s390/net/ctctty.h
Normale Datei
37
drivers/s390/net/ctctty.h
Normale Datei
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* $Id: ctctty.h,v 1.4 2003/09/18 08:01:10 mschwide Exp $
|
||||
*
|
||||
* CTC / ESCON network driver, tty interface.
|
||||
*
|
||||
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
||||
* Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _CTCTTY_H_
|
||||
#define _CTCTTY_H_
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
extern int ctc_tty_register_netdev(struct net_device *);
|
||||
extern void ctc_tty_unregister_netdev(struct net_device *);
|
||||
extern void ctc_tty_netif_rx(struct sk_buff *);
|
||||
extern int ctc_tty_init(void);
|
||||
extern void ctc_tty_cleanup(void);
|
||||
extern void ctc_tty_setcarrier(struct net_device *, int);
|
||||
|
||||
#endif
|
166
drivers/s390/net/cu3088.c
Normale Datei
166
drivers/s390/net/cu3088.c
Normale Datei
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* $Id: cu3088.c,v 1.34 2004/06/15 13:16:27 pavlic Exp $
|
||||
*
|
||||
* CTC / LCS ccw_device driver
|
||||
*
|
||||
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
||||
* Author(s): Arnd Bergmann <arndb@de.ibm.com>
|
||||
* Cornelia Huck <cohuck@de.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/ccwdev.h>
|
||||
#include <asm/ccwgroup.h>
|
||||
|
||||
#include "cu3088.h"
|
||||
|
||||
const char *cu3088_type[] = {
|
||||
"not a channel",
|
||||
"CTC/A",
|
||||
"ESCON channel",
|
||||
"FICON channel",
|
||||
"P390 LCS card",
|
||||
"OSA LCS card",
|
||||
"unknown channel type",
|
||||
"unsupported channel type",
|
||||
};
|
||||
|
||||
/* static definitions */
|
||||
|
||||
static struct ccw_device_id cu3088_ids[] = {
|
||||
{ CCW_DEVICE(0x3088, 0x08), .driver_info = channel_type_parallel },
|
||||
{ CCW_DEVICE(0x3088, 0x1f), .driver_info = channel_type_escon },
|
||||
{ CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon },
|
||||
{ CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 },
|
||||
{ CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 },
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
static struct ccw_driver cu3088_driver;
|
||||
|
||||
struct device *cu3088_root_dev;
|
||||
|
||||
static ssize_t
|
||||
group_write(struct device_driver *drv, const char *buf, size_t count)
|
||||
{
|
||||
const char *start, *end;
|
||||
char bus_ids[2][BUS_ID_SIZE], *argv[2];
|
||||
int i;
|
||||
int ret;
|
||||
struct ccwgroup_driver *cdrv;
|
||||
|
||||
cdrv = to_ccwgroupdrv(drv);
|
||||
if (!cdrv)
|
||||
return -EINVAL;
|
||||
start = buf;
|
||||
for (i=0; i<2; i++) {
|
||||
static const char delim[] = {',', '\n'};
|
||||
int len;
|
||||
|
||||
if (!(end = strchr(start, delim[i])))
|
||||
return count;
|
||||
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
|
||||
strlcpy (bus_ids[i], start, len);
|
||||
argv[i] = bus_ids[i];
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
|
||||
&cu3088_driver, 2, argv);
|
||||
|
||||
return (ret == 0) ? count : ret;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(group, 0200, NULL, group_write);
|
||||
|
||||
/* Register-unregister for ctc&lcs */
|
||||
int
|
||||
register_cu3088_discipline(struct ccwgroup_driver *dcp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!dcp)
|
||||
return -EINVAL;
|
||||
|
||||
/* Register discipline.*/
|
||||
rc = ccwgroup_driver_register(dcp);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = driver_create_file(&dcp->driver, &driver_attr_group);
|
||||
if (rc)
|
||||
ccwgroup_driver_unregister(dcp);
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
unregister_cu3088_discipline(struct ccwgroup_driver *dcp)
|
||||
{
|
||||
if (!dcp)
|
||||
return;
|
||||
|
||||
driver_remove_file(&dcp->driver, &driver_attr_group);
|
||||
ccwgroup_driver_unregister(dcp);
|
||||
}
|
||||
|
||||
static struct ccw_driver cu3088_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.ids = cu3088_ids,
|
||||
.name = "cu3088",
|
||||
.probe = ccwgroup_probe_ccwdev,
|
||||
.remove = ccwgroup_remove_ccwdev,
|
||||
};
|
||||
|
||||
/* module setup */
|
||||
static int __init
|
||||
cu3088_init (void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
cu3088_root_dev = s390_root_dev_register("cu3088");
|
||||
if (IS_ERR(cu3088_root_dev))
|
||||
return PTR_ERR(cu3088_root_dev);
|
||||
rc = ccw_driver_register(&cu3088_driver);
|
||||
if (rc)
|
||||
s390_root_dev_unregister(cu3088_root_dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
cu3088_exit (void)
|
||||
{
|
||||
ccw_driver_unregister(&cu3088_driver);
|
||||
s390_root_dev_unregister(cu3088_root_dev);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(ccw,cu3088_ids);
|
||||
MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(cu3088_init);
|
||||
module_exit(cu3088_exit);
|
||||
|
||||
EXPORT_SYMBOL_GPL(cu3088_type);
|
||||
EXPORT_SYMBOL_GPL(register_cu3088_discipline);
|
||||
EXPORT_SYMBOL_GPL(unregister_cu3088_discipline);
|
41
drivers/s390/net/cu3088.h
Normale Datei
41
drivers/s390/net/cu3088.h
Normale Datei
@@ -0,0 +1,41 @@
|
||||
#ifndef _CU3088_H
|
||||
#define _CU3088_H
|
||||
|
||||
/**
|
||||
* Enum for classifying detected devices.
|
||||
*/
|
||||
enum channel_types {
|
||||
/* Device is not a channel */
|
||||
channel_type_none,
|
||||
|
||||
/* Device is a CTC/A */
|
||||
channel_type_parallel,
|
||||
|
||||
/* Device is a ESCON channel */
|
||||
channel_type_escon,
|
||||
|
||||
/* Device is a FICON channel */
|
||||
channel_type_ficon,
|
||||
|
||||
/* Device is a P390 LCS card */
|
||||
channel_type_p390,
|
||||
|
||||
/* Device is a OSA2 card */
|
||||
channel_type_osa2,
|
||||
|
||||
/* Device is a channel, but we don't know
|
||||
* anything about it */
|
||||
channel_type_unknown,
|
||||
|
||||
/* Device is an unsupported model */
|
||||
channel_type_unsupported,
|
||||
|
||||
/* number of type entries */
|
||||
num_channel_types
|
||||
};
|
||||
|
||||
extern const char *cu3088_type[num_channel_types];
|
||||
extern int register_cu3088_discipline(struct ccwgroup_driver *);
|
||||
extern void unregister_cu3088_discipline(struct ccwgroup_driver *);
|
||||
|
||||
#endif
|
220
drivers/s390/net/fsm.c
Normale Datei
220
drivers/s390/net/fsm.c
Normale Datei
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* $Id: fsm.c,v 1.6 2003/10/15 11:37:29 mschwide Exp $
|
||||
*
|
||||
* A generic FSM based on fsm used in isdn4linux
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fsm.h"
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
|
||||
MODULE_DESCRIPTION("Finite state machine helper functions");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
fsm_instance *
|
||||
init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
|
||||
int nr_events, const fsm_node *tmpl, int tmpl_len, int order)
|
||||
{
|
||||
int i;
|
||||
fsm_instance *this;
|
||||
fsm_function_t *m;
|
||||
fsm *f;
|
||||
|
||||
this = (fsm_instance *)kmalloc(sizeof(fsm_instance), order);
|
||||
if (this == NULL) {
|
||||
printk(KERN_WARNING
|
||||
"fsm(%s): init_fsm: Couldn't alloc instance\n", name);
|
||||
return NULL;
|
||||
}
|
||||
memset(this, 0, sizeof(fsm_instance));
|
||||
strlcpy(this->name, name, sizeof(this->name));
|
||||
|
||||
f = (fsm *)kmalloc(sizeof(fsm), order);
|
||||
if (f == NULL) {
|
||||
printk(KERN_WARNING
|
||||
"fsm(%s): init_fsm: Couldn't alloc fsm\n", name);
|
||||
kfree_fsm(this);
|
||||
return NULL;
|
||||
}
|
||||
memset(f, 0, sizeof(fsm));
|
||||
f->nr_events = nr_events;
|
||||
f->nr_states = nr_states;
|
||||
f->event_names = event_names;
|
||||
f->state_names = state_names;
|
||||
this->f = f;
|
||||
|
||||
m = (fsm_function_t *)kmalloc(
|
||||
sizeof(fsm_function_t) * nr_states * nr_events, order);
|
||||
if (m == NULL) {
|
||||
printk(KERN_WARNING
|
||||
"fsm(%s): init_fsm: Couldn't alloc jumptable\n", name);
|
||||
kfree_fsm(this);
|
||||
return NULL;
|
||||
}
|
||||
memset(m, 0, sizeof(fsm_function_t) * f->nr_states * f->nr_events);
|
||||
f->jumpmatrix = m;
|
||||
|
||||
for (i = 0; i < tmpl_len; i++) {
|
||||
if ((tmpl[i].cond_state >= nr_states) ||
|
||||
(tmpl[i].cond_event >= nr_events) ) {
|
||||
printk(KERN_ERR
|
||||
"fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",
|
||||
name, i, (long)tmpl[i].cond_state, (long)f->nr_states,
|
||||
(long)tmpl[i].cond_event, (long)f->nr_events);
|
||||
kfree_fsm(this);
|
||||
return NULL;
|
||||
} else
|
||||
m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =
|
||||
tmpl[i].function;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
kfree_fsm(fsm_instance *this)
|
||||
{
|
||||
if (this) {
|
||||
if (this->f) {
|
||||
if (this->f->jumpmatrix)
|
||||
kfree(this->f->jumpmatrix);
|
||||
kfree(this->f);
|
||||
}
|
||||
kfree(this);
|
||||
} else
|
||||
printk(KERN_WARNING
|
||||
"fsm: kfree_fsm called with NULL argument\n");
|
||||
}
|
||||
|
||||
#if FSM_DEBUG_HISTORY
|
||||
void
|
||||
fsm_print_history(fsm_instance *fi)
|
||||
{
|
||||
int idx = 0;
|
||||
int i;
|
||||
|
||||
if (fi->history_size >= FSM_HISTORY_SIZE)
|
||||
idx = fi->history_index;
|
||||
|
||||
printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);
|
||||
for (i = 0; i < fi->history_size; i++) {
|
||||
int e = fi->history[idx].event;
|
||||
int s = fi->history[idx++].state;
|
||||
idx %= FSM_HISTORY_SIZE;
|
||||
if (e == -1)
|
||||
printk(KERN_DEBUG " S=%s\n",
|
||||
fi->f->state_names[s]);
|
||||
else
|
||||
printk(KERN_DEBUG " S=%s E=%s\n",
|
||||
fi->f->state_names[s],
|
||||
fi->f->event_names[e]);
|
||||
}
|
||||
fi->history_size = fi->history_index = 0;
|
||||
}
|
||||
|
||||
void
|
||||
fsm_record_history(fsm_instance *fi, int state, int event)
|
||||
{
|
||||
fi->history[fi->history_index].state = state;
|
||||
fi->history[fi->history_index++].event = event;
|
||||
fi->history_index %= FSM_HISTORY_SIZE;
|
||||
if (fi->history_size < FSM_HISTORY_SIZE)
|
||||
fi->history_size++;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *
|
||||
fsm_getstate_str(fsm_instance *fi)
|
||||
{
|
||||
int st = atomic_read(&fi->state);
|
||||
if (st >= fi->f->nr_states)
|
||||
return "Invalid";
|
||||
return fi->f->state_names[st];
|
||||
}
|
||||
|
||||
static void
|
||||
fsm_expire_timer(fsm_timer *this)
|
||||
{
|
||||
#if FSM_TIMER_DEBUG
|
||||
printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",
|
||||
this->fi->name, this);
|
||||
#endif
|
||||
fsm_event(this->fi, this->expire_event, this->event_arg);
|
||||
}
|
||||
|
||||
void
|
||||
fsm_settimer(fsm_instance *fi, fsm_timer *this)
|
||||
{
|
||||
this->fi = fi;
|
||||
this->tl.function = (void *)fsm_expire_timer;
|
||||
this->tl.data = (long)this;
|
||||
#if FSM_TIMER_DEBUG
|
||||
printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,
|
||||
this);
|
||||
#endif
|
||||
init_timer(&this->tl);
|
||||
}
|
||||
|
||||
void
|
||||
fsm_deltimer(fsm_timer *this)
|
||||
{
|
||||
#if FSM_TIMER_DEBUG
|
||||
printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,
|
||||
this);
|
||||
#endif
|
||||
del_timer(&this->tl);
|
||||
}
|
||||
|
||||
int
|
||||
fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)
|
||||
{
|
||||
|
||||
#if FSM_TIMER_DEBUG
|
||||
printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",
|
||||
this->fi->name, this, millisec);
|
||||
#endif
|
||||
|
||||
init_timer(&this->tl);
|
||||
this->tl.function = (void *)fsm_expire_timer;
|
||||
this->tl.data = (long)this;
|
||||
this->expire_event = event;
|
||||
this->event_arg = arg;
|
||||
this->tl.expires = jiffies + (millisec * HZ) / 1000;
|
||||
add_timer(&this->tl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: this function is never used, why */
|
||||
void
|
||||
fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
|
||||
{
|
||||
|
||||
#if FSM_TIMER_DEBUG
|
||||
printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",
|
||||
this->fi->name, this, millisec);
|
||||
#endif
|
||||
|
||||
del_timer(&this->tl);
|
||||
init_timer(&this->tl);
|
||||
this->tl.function = (void *)fsm_expire_timer;
|
||||
this->tl.data = (long)this;
|
||||
this->expire_event = event;
|
||||
this->event_arg = arg;
|
||||
this->tl.expires = jiffies + (millisec * HZ) / 1000;
|
||||
add_timer(&this->tl);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(init_fsm);
|
||||
EXPORT_SYMBOL(kfree_fsm);
|
||||
EXPORT_SYMBOL(fsm_settimer);
|
||||
EXPORT_SYMBOL(fsm_deltimer);
|
||||
EXPORT_SYMBOL(fsm_addtimer);
|
||||
EXPORT_SYMBOL(fsm_modtimer);
|
||||
EXPORT_SYMBOL(fsm_getstate_str);
|
||||
|
||||
#if FSM_DEBUG_HISTORY
|
||||
EXPORT_SYMBOL(fsm_print_history);
|
||||
EXPORT_SYMBOL(fsm_record_history);
|
||||
#endif
|
265
drivers/s390/net/fsm.h
Normale Datei
265
drivers/s390/net/fsm.h
Normale Datei
@@ -0,0 +1,265 @@
|
||||
/* $Id: fsm.h,v 1.1.1.1 2002/03/13 19:33:09 mschwide Exp $
|
||||
*/
|
||||
#ifndef _FSM_H_
|
||||
#define _FSM_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
/**
|
||||
* Define this to get debugging messages.
|
||||
*/
|
||||
#define FSM_DEBUG 0
|
||||
|
||||
/**
|
||||
* Define this to get debugging massages for
|
||||
* timer handling.
|
||||
*/
|
||||
#define FSM_TIMER_DEBUG 0
|
||||
|
||||
/**
|
||||
* Define these to record a history of
|
||||
* Events/Statechanges and print it if a
|
||||
* action_function is not found.
|
||||
*/
|
||||
#define FSM_DEBUG_HISTORY 0
|
||||
#define FSM_HISTORY_SIZE 40
|
||||
|
||||
struct fsm_instance_t;
|
||||
|
||||
/**
|
||||
* Definition of an action function, called by a FSM
|
||||
*/
|
||||
typedef void (*fsm_function_t)(struct fsm_instance_t *, int, void *);
|
||||
|
||||
/**
|
||||
* Internal jump table for a FSM
|
||||
*/
|
||||
typedef struct {
|
||||
fsm_function_t *jumpmatrix;
|
||||
int nr_events;
|
||||
int nr_states;
|
||||
const char **event_names;
|
||||
const char **state_names;
|
||||
} fsm;
|
||||
|
||||
#if FSM_DEBUG_HISTORY
|
||||
/**
|
||||
* Element of State/Event history used for debugging.
|
||||
*/
|
||||
typedef struct {
|
||||
int state;
|
||||
int event;
|
||||
} fsm_history;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Representation of a FSM
|
||||
*/
|
||||
typedef struct fsm_instance_t {
|
||||
fsm *f;
|
||||
atomic_t state;
|
||||
char name[16];
|
||||
void *userdata;
|
||||
int userint;
|
||||
#if FSM_DEBUG_HISTORY
|
||||
int history_index;
|
||||
int history_size;
|
||||
fsm_history history[FSM_HISTORY_SIZE];
|
||||
#endif
|
||||
} fsm_instance;
|
||||
|
||||
/**
|
||||
* Description of a state-event combination
|
||||
*/
|
||||
typedef struct {
|
||||
int cond_state;
|
||||
int cond_event;
|
||||
fsm_function_t function;
|
||||
} fsm_node;
|
||||
|
||||
/**
|
||||
* Description of a FSM Timer.
|
||||
*/
|
||||
typedef struct {
|
||||
fsm_instance *fi;
|
||||
struct timer_list tl;
|
||||
int expire_event;
|
||||
void *event_arg;
|
||||
} fsm_timer;
|
||||
|
||||
/**
|
||||
* Creates an FSM
|
||||
*
|
||||
* @param name Name of this instance for logging purposes.
|
||||
* @param state_names An array of names for all states for logging purposes.
|
||||
* @param event_names An array of names for all events for logging purposes.
|
||||
* @param nr_states Number of states for this instance.
|
||||
* @param nr_events Number of events for this instance.
|
||||
* @param tmpl An array of fsm_nodes, describing this FSM.
|
||||
* @param tmpl_len Length of the describing array.
|
||||
* @param order Parameter for allocation of the FSM data structs.
|
||||
*/
|
||||
extern fsm_instance *
|
||||
init_fsm(char *name, const char **state_names,
|
||||
const char **event_names,
|
||||
int nr_states, int nr_events, const fsm_node *tmpl,
|
||||
int tmpl_len, int order);
|
||||
|
||||
/**
|
||||
* Releases an FSM
|
||||
*
|
||||
* @param fi Pointer to an FSM, previously created with init_fsm.
|
||||
*/
|
||||
extern void kfree_fsm(fsm_instance *fi);
|
||||
|
||||
#if FSM_DEBUG_HISTORY
|
||||
extern void
|
||||
fsm_print_history(fsm_instance *fi);
|
||||
|
||||
extern void
|
||||
fsm_record_history(fsm_instance *fi, int state, int event);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Emits an event to a FSM.
|
||||
* If an action function is defined for the current state/event combination,
|
||||
* this function is called.
|
||||
*
|
||||
* @param fi Pointer to FSM which should receive the event.
|
||||
* @param event The event do be delivered.
|
||||
* @param arg A generic argument, handed to the action function.
|
||||
*
|
||||
* @return 0 on success,
|
||||
* 1 if current state or event is out of range
|
||||
* !0 if state and event in range, but no action defined.
|
||||
*/
|
||||
extern __inline__ int
|
||||
fsm_event(fsm_instance *fi, int event, void *arg)
|
||||
{
|
||||
fsm_function_t r;
|
||||
int state = atomic_read(&fi->state);
|
||||
|
||||
if ((state >= fi->f->nr_states) ||
|
||||
(event >= fi->f->nr_events) ) {
|
||||
printk(KERN_ERR "fsm(%s): Invalid state st(%ld/%ld) ev(%d/%ld)\n",
|
||||
fi->name, (long)state,(long)fi->f->nr_states, event,
|
||||
(long)fi->f->nr_events);
|
||||
#if FSM_DEBUG_HISTORY
|
||||
fsm_print_history(fi);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
r = fi->f->jumpmatrix[fi->f->nr_states * event + state];
|
||||
if (r) {
|
||||
#if FSM_DEBUG
|
||||
printk(KERN_DEBUG "fsm(%s): state %s event %s\n",
|
||||
fi->name, fi->f->state_names[state],
|
||||
fi->f->event_names[event]);
|
||||
#endif
|
||||
#if FSM_DEBUG_HISTORY
|
||||
fsm_record_history(fi, state, event);
|
||||
#endif
|
||||
r(fi, event, arg);
|
||||
return 0;
|
||||
} else {
|
||||
#if FSM_DEBUG || FSM_DEBUG_HISTORY
|
||||
printk(KERN_DEBUG "fsm(%s): no function for event %s in state %s\n",
|
||||
fi->name, fi->f->event_names[event],
|
||||
fi->f->state_names[state]);
|
||||
#endif
|
||||
#if FSM_DEBUG_HISTORY
|
||||
fsm_print_history(fi);
|
||||
#endif
|
||||
return !0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the state of an FSM.
|
||||
* This does <em>not</em> trigger an event or calls an action function.
|
||||
*
|
||||
* @param fi Pointer to FSM
|
||||
* @param state The new state for this FSM.
|
||||
*/
|
||||
extern __inline__ void
|
||||
fsm_newstate(fsm_instance *fi, int newstate)
|
||||
{
|
||||
atomic_set(&fi->state,newstate);
|
||||
#if FSM_DEBUG_HISTORY
|
||||
fsm_record_history(fi, newstate, -1);
|
||||
#endif
|
||||
#if FSM_DEBUG
|
||||
printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name,
|
||||
fi->f->state_names[newstate]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the state of an FSM
|
||||
*
|
||||
* @param fi Pointer to FSM
|
||||
*
|
||||
* @return The current state of the FSM.
|
||||
*/
|
||||
extern __inline__ int
|
||||
fsm_getstate(fsm_instance *fi)
|
||||
{
|
||||
return atomic_read(&fi->state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the name of the state of an FSM
|
||||
*
|
||||
* @param fi Pointer to FSM
|
||||
*
|
||||
* @return The current state of the FSM in a human readable form.
|
||||
*/
|
||||
extern const char *fsm_getstate_str(fsm_instance *fi);
|
||||
|
||||
/**
|
||||
* Initializes a timer for an FSM.
|
||||
* This prepares an fsm_timer for usage with fsm_addtimer.
|
||||
*
|
||||
* @param fi Pointer to FSM
|
||||
* @param timer The timer to be initialized.
|
||||
*/
|
||||
extern void fsm_settimer(fsm_instance *fi, fsm_timer *);
|
||||
|
||||
/**
|
||||
* Clears a pending timer of an FSM instance.
|
||||
*
|
||||
* @param timer The timer to clear.
|
||||
*/
|
||||
extern void fsm_deltimer(fsm_timer *timer);
|
||||
|
||||
/**
|
||||
* Adds and starts a timer to an FSM instance.
|
||||
*
|
||||
* @param timer The timer to be added. The field fi of that timer
|
||||
* must have been set to point to the instance.
|
||||
* @param millisec Duration, after which the timer should expire.
|
||||
* @param event Event, to trigger if timer expires.
|
||||
* @param arg Generic argument, provided to expiry function.
|
||||
*
|
||||
* @return 0 on success, -1 if timer is already active.
|
||||
*/
|
||||
extern int fsm_addtimer(fsm_timer *timer, int millisec, int event, void *arg);
|
||||
|
||||
/**
|
||||
* Modifies a timer of an FSM.
|
||||
*
|
||||
* @param timer The timer to modify.
|
||||
* @param millisec Duration, after which the timer should expire.
|
||||
* @param event Event, to trigger if timer expires.
|
||||
* @param arg Generic argument, provided to expiry function.
|
||||
*/
|
||||
extern void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg);
|
||||
|
||||
#endif /* _FSM_H_ */
|
2567
drivers/s390/net/iucv.c
Normale Datei
2567
drivers/s390/net/iucv.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
849
drivers/s390/net/iucv.h
Normale Datei
849
drivers/s390/net/iucv.h
Normale Datei
@@ -0,0 +1,849 @@
|
||||
/*
|
||||
* drivers/s390/net/iucv.h
|
||||
* IUCV base support.
|
||||
*
|
||||
* S390 version
|
||||
* Copyright (C) 2000 IBM Corporation
|
||||
* Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
|
||||
* Xenia Tkatschow (xenia@us.ibm.com)
|
||||
*
|
||||
*
|
||||
* Functionality:
|
||||
* To explore any of the IUCV functions, one must first register
|
||||
* their program using iucv_register_program(). Once your program has
|
||||
* successfully completed a register, it can exploit the other functions.
|
||||
* For furthur reference on all IUCV functionality, refer to the
|
||||
* CP Programming Services book, also available on the web
|
||||
* thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
|
||||
*
|
||||
* Definition of Return Codes
|
||||
* -All positive return codes including zero are reflected back
|
||||
* from CP except for iucv_register_program. The definition of each
|
||||
* return code can be found in CP Programming Services book.
|
||||
* Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
|
||||
* - Return Code of:
|
||||
* (-EINVAL) Invalid value
|
||||
* (-ENOMEM) storage allocation failed
|
||||
* pgmask defined in iucv_register_program will be set depending on input
|
||||
* paramters.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
/**
|
||||
* Debug Facility stuff
|
||||
*/
|
||||
#define IUCV_DBF_SETUP_NAME "iucv_setup"
|
||||
#define IUCV_DBF_SETUP_LEN 32
|
||||
#define IUCV_DBF_SETUP_INDEX 1
|
||||
#define IUCV_DBF_SETUP_NR_AREAS 1
|
||||
#define IUCV_DBF_SETUP_LEVEL 3
|
||||
|
||||
#define IUCV_DBF_DATA_NAME "iucv_data"
|
||||
#define IUCV_DBF_DATA_LEN 128
|
||||
#define IUCV_DBF_DATA_INDEX 1
|
||||
#define IUCV_DBF_DATA_NR_AREAS 1
|
||||
#define IUCV_DBF_DATA_LEVEL 2
|
||||
|
||||
#define IUCV_DBF_TRACE_NAME "iucv_trace"
|
||||
#define IUCV_DBF_TRACE_LEN 16
|
||||
#define IUCV_DBF_TRACE_INDEX 2
|
||||
#define IUCV_DBF_TRACE_NR_AREAS 1
|
||||
#define IUCV_DBF_TRACE_LEVEL 3
|
||||
|
||||
#define IUCV_DBF_TEXT(name,level,text) \
|
||||
do { \
|
||||
debug_text_event(iucv_dbf_##name,level,text); \
|
||||
} while (0)
|
||||
|
||||
#define IUCV_DBF_HEX(name,level,addr,len) \
|
||||
do { \
|
||||
debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
|
||||
} while (0)
|
||||
|
||||
DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
|
||||
|
||||
#define IUCV_DBF_TEXT_(name,level,text...) \
|
||||
do { \
|
||||
char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
|
||||
sprintf(iucv_dbf_txt_buf, text); \
|
||||
debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
|
||||
put_cpu_var(iucv_dbf_txt_buf); \
|
||||
} while (0)
|
||||
|
||||
#define IUCV_DBF_SPRINTF(name,level,text...) \
|
||||
do { \
|
||||
debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
|
||||
debug_sprintf_event(iucv_dbf_trace, level, text ); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* some more debug stuff
|
||||
*/
|
||||
#define IUCV_HEXDUMP16(importance,header,ptr) \
|
||||
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
|
||||
*(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
|
||||
*(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
|
||||
*(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
|
||||
*(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
|
||||
*(((char*)ptr)+12),*(((char*)ptr)+13), \
|
||||
*(((char*)ptr)+14),*(((char*)ptr)+15)); \
|
||||
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
|
||||
*(((char*)ptr)+16),*(((char*)ptr)+17), \
|
||||
*(((char*)ptr)+18),*(((char*)ptr)+19), \
|
||||
*(((char*)ptr)+20),*(((char*)ptr)+21), \
|
||||
*(((char*)ptr)+22),*(((char*)ptr)+23), \
|
||||
*(((char*)ptr)+24),*(((char*)ptr)+25), \
|
||||
*(((char*)ptr)+26),*(((char*)ptr)+27), \
|
||||
*(((char*)ptr)+28),*(((char*)ptr)+29), \
|
||||
*(((char*)ptr)+30),*(((char*)ptr)+31));
|
||||
|
||||
static inline void
|
||||
iucv_hex_dump(unsigned char *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i && !(i % 16))
|
||||
printk("\n");
|
||||
printk("%02x ", *(buf + i));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
/**
|
||||
* end of debug stuff
|
||||
*/
|
||||
|
||||
#define uchar unsigned char
|
||||
#define ushort unsigned short
|
||||
#define ulong unsigned long
|
||||
#define iucv_handle_t void *
|
||||
|
||||
/* flags1:
|
||||
* All flags are defined in the field IPFLAGS1 of each function
|
||||
* and can be found in CP Programming Services.
|
||||
* IPLOCAL - Indicates the connect can only be satisfied on the
|
||||
* local system
|
||||
* IPPRTY - Indicates a priority message
|
||||
* IPQUSCE - Indicates you do not want to receive messages on a
|
||||
* path until an iucv_resume is issued
|
||||
* IPRMDATA - Indicates that the message is in the parameter list
|
||||
*/
|
||||
#define IPLOCAL 0x01
|
||||
#define IPPRTY 0x20
|
||||
#define IPQUSCE 0x40
|
||||
#define IPRMDATA 0x80
|
||||
|
||||
/* flags1_out:
|
||||
* All flags are defined in the output field of IPFLAGS1 for each function
|
||||
* and can be found in CP Programming Services.
|
||||
* IPNORPY - Specifies this is a one-way message and no reply is expected.
|
||||
* IPPRTY - Indicates a priority message is permitted. Defined in flags1.
|
||||
*/
|
||||
#define IPNORPY 0x10
|
||||
|
||||
#define Nonpriority_MessagePendingInterruptsFlag 0x80
|
||||
#define Priority_MessagePendingInterruptsFlag 0x40
|
||||
#define Nonpriority_MessageCompletionInterruptsFlag 0x20
|
||||
#define Priority_MessageCompletionInterruptsFlag 0x10
|
||||
#define IUCVControlInterruptsFlag 0x08
|
||||
#define AllInterrupts 0xf8
|
||||
/*
|
||||
* Mapping of external interrupt buffers should be used with the corresponding
|
||||
* interrupt types.
|
||||
* Names: iucv_ConnectionPending -> connection pending
|
||||
* iucv_ConnectionComplete -> connection complete
|
||||
* iucv_ConnectionSevered -> connection severed
|
||||
* iucv_ConnectionQuiesced -> connection quiesced
|
||||
* iucv_ConnectionResumed -> connection resumed
|
||||
* iucv_MessagePending -> message pending
|
||||
* iucv_MessageComplete -> message complete
|
||||
*/
|
||||
typedef struct {
|
||||
u16 ippathid;
|
||||
uchar ipflags1;
|
||||
uchar iptype;
|
||||
u16 ipmsglim;
|
||||
u16 res1;
|
||||
uchar ipvmid[8];
|
||||
uchar ipuser[16];
|
||||
u32 res3;
|
||||
uchar ippollfg;
|
||||
uchar res4[3];
|
||||
} iucv_ConnectionPending;
|
||||
|
||||
typedef struct {
|
||||
u16 ippathid;
|
||||
uchar ipflags1;
|
||||
uchar iptype;
|
||||
u16 ipmsglim;
|
||||
u16 res1;
|
||||
uchar res2[8];
|
||||
uchar ipuser[16];
|
||||
u32 res3;
|
||||
uchar ippollfg;
|
||||
uchar res4[3];
|
||||
} iucv_ConnectionComplete;
|
||||
|
||||
typedef struct {
|
||||
u16 ippathid;
|
||||
uchar res1;
|
||||
uchar iptype;
|
||||
u32 res2;
|
||||
uchar res3[8];
|
||||
uchar ipuser[16];
|
||||
u32 res4;
|
||||
uchar ippollfg;
|
||||
uchar res5[3];
|
||||
} iucv_ConnectionSevered;
|
||||
|
||||
typedef struct {
|
||||
u16 ippathid;
|
||||
uchar res1;
|
||||
uchar iptype;
|
||||
u32 res2;
|
||||
uchar res3[8];
|
||||
uchar ipuser[16];
|
||||
u32 res4;
|
||||
uchar ippollfg;
|
||||
uchar res5[3];
|
||||
} iucv_ConnectionQuiesced;
|
||||
|
||||
typedef struct {
|
||||
u16 ippathid;
|
||||
uchar res1;
|
||||
uchar iptype;
|
||||
u32 res2;
|
||||
uchar res3[8];
|
||||
uchar ipuser[16];
|
||||
u32 res4;
|
||||
uchar ippollfg;
|
||||
uchar res5[3];
|
||||
} iucv_ConnectionResumed;
|
||||
|
||||
typedef struct {
|
||||
u16 ippathid;
|
||||
uchar ipflags1;
|
||||
uchar iptype;
|
||||
u32 ipmsgid;
|
||||
u32 iptrgcls;
|
||||
union u2 {
|
||||
u32 iprmmsg1_u32;
|
||||
uchar iprmmsg1[4];
|
||||
} ln1msg1;
|
||||
union u1 {
|
||||
u32 ipbfln1f;
|
||||
uchar iprmmsg2[4];
|
||||
} ln1msg2;
|
||||
u32 res1[3];
|
||||
u32 ipbfln2f;
|
||||
uchar ippollfg;
|
||||
uchar res2[3];
|
||||
} iucv_MessagePending;
|
||||
|
||||
typedef struct {
|
||||
u16 ippathid;
|
||||
uchar ipflags1;
|
||||
uchar iptype;
|
||||
u32 ipmsgid;
|
||||
u32 ipaudit;
|
||||
uchar iprmmsg[8];
|
||||
u32 ipsrccls;
|
||||
u32 ipmsgtag;
|
||||
u32 res;
|
||||
u32 ipbfln2f;
|
||||
uchar ippollfg;
|
||||
uchar res2[3];
|
||||
} iucv_MessageComplete;
|
||||
|
||||
/*
|
||||
* iucv_interrupt_ops_t: Is a vector of functions that handle
|
||||
* IUCV interrupts.
|
||||
* Parameter list:
|
||||
* eib - is a pointer to a 40-byte area described
|
||||
* with one of the structures above.
|
||||
* pgm_data - this data is strictly for the
|
||||
* interrupt handler that is passed by
|
||||
* the application. This may be an address
|
||||
* or token.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*ConnectionPending) (iucv_ConnectionPending * eib,
|
||||
void *pgm_data);
|
||||
void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
|
||||
void *pgm_data);
|
||||
void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
|
||||
void *pgm_data);
|
||||
void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
|
||||
void *pgm_data);
|
||||
void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
|
||||
void *pgm_data);
|
||||
void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
|
||||
void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
|
||||
} iucv_interrupt_ops_t;
|
||||
|
||||
/*
|
||||
*iucv_array_t : Defines buffer array.
|
||||
* Inside the array may be 31- bit addresses and 31-bit lengths.
|
||||
*/
|
||||
typedef struct {
|
||||
u32 address;
|
||||
u32 length;
|
||||
} iucv_array_t __attribute__ ((aligned (8)));
|
||||
|
||||
extern struct bus_type iucv_bus;
|
||||
extern struct device *iucv_root;
|
||||
|
||||
/* -prototypes- */
|
||||
/*
|
||||
* Name: iucv_register_program
|
||||
* Purpose: Registers an application with IUCV
|
||||
* Input: prmname - user identification
|
||||
* userid - machine identification
|
||||
* pgmmask - indicates which bits in the prmname and userid combined will be
|
||||
* used to determine who is given control
|
||||
* ops - address of vector of interrupt handlers
|
||||
* pgm_data- application data passed to interrupt handlers
|
||||
* Output: NA
|
||||
* Return: address of handler
|
||||
* (0) - Error occurred, registration not completed.
|
||||
* NOTE: Exact cause of failure will be recorded in syslog.
|
||||
*/
|
||||
iucv_handle_t iucv_register_program (uchar pgmname[16],
|
||||
uchar userid[8],
|
||||
uchar pgmmask[24],
|
||||
iucv_interrupt_ops_t * ops,
|
||||
void *pgm_data);
|
||||
|
||||
/*
|
||||
* Name: iucv_unregister_program
|
||||
* Purpose: Unregister application with IUCV
|
||||
* Input: address of handler
|
||||
* Output: NA
|
||||
* Return: (0) - Normal return
|
||||
* (-EINVAL) - Internal error, wild pointer
|
||||
*/
|
||||
int iucv_unregister_program (iucv_handle_t handle);
|
||||
|
||||
/*
|
||||
* Name: iucv_accept
|
||||
* Purpose: This function is issued after the user receives a Connection Pending external
|
||||
* interrupt and now wishes to complete the IUCV communication path.
|
||||
* Input: pathid - u16 , Path identification number
|
||||
* msglim_reqstd - u16, The number of outstanding messages requested.
|
||||
* user_data - uchar[16], Data specified by the iucv_connect function.
|
||||
* flags1 - int, Contains options for this path.
|
||||
* -IPPRTY - 0x20- Specifies if you want to send priority message.
|
||||
* -IPRMDATA - 0x80, Specifies whether your program can handle a message
|
||||
* in the parameter list.
|
||||
* -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
|
||||
* established.
|
||||
* handle - iucv_handle_t, Address of handler.
|
||||
* pgm_data - void *, Application data passed to interrupt handlers.
|
||||
* flags1_out - int * Contains information about the path
|
||||
* - IPPRTY - 0x20, Indicates you may send priority messages.
|
||||
* msglim - *u16, Number of outstanding messages.
|
||||
* Output: return code from CP IUCV call.
|
||||
*/
|
||||
|
||||
int iucv_accept (u16 pathid,
|
||||
u16 msglim_reqstd,
|
||||
uchar user_data[16],
|
||||
int flags1,
|
||||
iucv_handle_t handle,
|
||||
void *pgm_data, int *flags1_out, u16 * msglim);
|
||||
|
||||
/*
|
||||
* Name: iucv_connect
|
||||
* Purpose: This function establishes an IUCV path. Although the connect may complete
|
||||
* successfully, you are not able to use the path until you receive an IUCV
|
||||
* Connection Complete external interrupt.
|
||||
* Input: pathid - u16 *, Path identification number
|
||||
* msglim_reqstd - u16, Number of outstanding messages requested
|
||||
* user_data - uchar[16], 16-byte user data
|
||||
* userid - uchar[8], User identification
|
||||
* system_name - uchar[8], 8-byte identifying the system name
|
||||
* flags1 - int, Contains options for this path.
|
||||
* -IPPRTY - 0x20, Specifies if you want to send priority message.
|
||||
* -IPRMDATA - 0x80, Specifies whether your program can handle a message
|
||||
* in the parameter list.
|
||||
* -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
|
||||
* established.
|
||||
* -IPLOCAL - 0X01, Allows an application to force the partner to be on
|
||||
* the local system. If local is specified then target class cannot be
|
||||
* specified.
|
||||
* flags1_out - int * Contains information about the path
|
||||
* - IPPRTY - 0x20, Indicates you may send priority messages.
|
||||
* msglim - * u16, Number of outstanding messages
|
||||
* handle - iucv_handle_t, Address of handler
|
||||
* pgm_data - void *, Application data passed to interrupt handlers
|
||||
* Output: return code from CP IUCV call
|
||||
* rc - return code from iucv_declare_buffer
|
||||
* -EINVAL - Invalid handle passed by application
|
||||
* -EINVAL - Pathid address is NULL
|
||||
* add_pathid_result - Return code from internal function add_pathid
|
||||
*/
|
||||
int
|
||||
iucv_connect (u16 * pathid,
|
||||
u16 msglim_reqstd,
|
||||
uchar user_data[16],
|
||||
uchar userid[8],
|
||||
uchar system_name[8],
|
||||
int flags1,
|
||||
int *flags1_out,
|
||||
u16 * msglim, iucv_handle_t handle, void *pgm_data);
|
||||
|
||||
/*
|
||||
* Name: iucv_purge
|
||||
* Purpose: This function cancels a message that you have sent.
|
||||
* Input: pathid - Path identification number.
|
||||
* msgid - Specifies the message ID of the message to be purged.
|
||||
* srccls - Specifies the source message class.
|
||||
* Output: audit - Contains information about asynchronous error
|
||||
* that may have affected the normal completion
|
||||
* of this message.
|
||||
* Return: Return code from CP IUCV call.
|
||||
*/
|
||||
int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit);
|
||||
/*
|
||||
* Name: iucv_query_maxconn
|
||||
* Purpose: This function determines the maximum number of communication paths you
|
||||
* may establish.
|
||||
* Return: maxconn - ulong, Maximum number of connection the virtual machine may
|
||||
* establish.
|
||||
*/
|
||||
ulong iucv_query_maxconn (void);
|
||||
|
||||
/*
|
||||
* Name: iucv_query_bufsize
|
||||
* Purpose: This function determines how large an external interrupt
|
||||
* buffer IUCV requires to store information.
|
||||
* Return: bufsize - ulong, Size of external interrupt buffer.
|
||||
*/
|
||||
ulong iucv_query_bufsize (void);
|
||||
|
||||
/*
|
||||
* Name: iucv_quiesce
|
||||
* Purpose: This function temporarily suspends incoming messages on an
|
||||
* IUCV path. You can later reactivate the path by invoking
|
||||
* the iucv_resume function.
|
||||
* Input: pathid - Path identification number
|
||||
* user_data - 16-bytes of user data
|
||||
* Output: NA
|
||||
* Return: Return code from CP IUCV call.
|
||||
*/
|
||||
int iucv_quiesce (u16 pathid, uchar user_data[16]);
|
||||
|
||||
/*
|
||||
* Name: iucv_receive
|
||||
* Purpose: This function receives messages that are being sent to you
|
||||
* over established paths. Data will be returned in buffer for length of
|
||||
* buflen.
|
||||
* Input:
|
||||
* pathid - Path identification number.
|
||||
* buffer - Address of buffer to receive.
|
||||
* buflen - Length of buffer to receive.
|
||||
* msgid - Specifies the message ID.
|
||||
* trgcls - Specifies target class.
|
||||
* Output:
|
||||
* flags1_out: int *, Contains information about this path.
|
||||
* IPNORPY - 0x10 Specifies this is a one-way message and no reply is
|
||||
* expected.
|
||||
* IPPRTY - 0x20 Specifies if you want to send priority message.
|
||||
* IPRMDATA - 0x80 specifies the data is contained in the parameter list
|
||||
* residual_buffer - address of buffer updated by the number
|
||||
* of bytes you have received.
|
||||
* residual_length -
|
||||
* Contains one of the following values, if the receive buffer is:
|
||||
* The same length as the message, this field is zero.
|
||||
* Longer than the message, this field contains the number of
|
||||
* bytes remaining in the buffer.
|
||||
* Shorter than the message, this field contains the residual
|
||||
* count (that is, the number of bytes remaining in the
|
||||
* message that does not fit into the buffer. In this
|
||||
* case b2f0_result = 5.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - buffer address is pointing to NULL
|
||||
*/
|
||||
int iucv_receive (u16 pathid,
|
||||
u32 msgid,
|
||||
u32 trgcls,
|
||||
void *buffer,
|
||||
ulong buflen,
|
||||
int *flags1_out,
|
||||
ulong * residual_buffer, ulong * residual_length);
|
||||
|
||||
/*
|
||||
* Name: iucv_receive_array
|
||||
* Purpose: This function receives messages that are being sent to you
|
||||
* over established paths. Data will be returned in first buffer for
|
||||
* length of first buffer.
|
||||
* Input: pathid - Path identification number.
|
||||
* msgid - specifies the message ID.
|
||||
* trgcls - Specifies target class.
|
||||
* buffer - Address of array of buffers.
|
||||
* buflen - Total length of buffers.
|
||||
* Output:
|
||||
* flags1_out: int *, Contains information about this path.
|
||||
* IPNORPY - 0x10 Specifies this is a one-way message and no reply is
|
||||
* expected.
|
||||
* IPPRTY - 0x20 Specifies if you want to send priority message.
|
||||
* IPRMDATA - 0x80 specifies the data is contained in the parameter list
|
||||
* residual_buffer - address points to the current list entry IUCV
|
||||
* is working on.
|
||||
* residual_length -
|
||||
* Contains one of the following values, if the receive buffer is:
|
||||
* The same length as the message, this field is zero.
|
||||
* Longer than the message, this field contains the number of
|
||||
* bytes remaining in the buffer.
|
||||
* Shorter than the message, this field contains the residual
|
||||
* count (that is, the number of bytes remaining in the
|
||||
* message that does not fit into the buffer. In this
|
||||
* case b2f0_result = 5.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer address is NULL.
|
||||
*/
|
||||
int iucv_receive_array (u16 pathid,
|
||||
u32 msgid,
|
||||
u32 trgcls,
|
||||
iucv_array_t * buffer,
|
||||
ulong buflen,
|
||||
int *flags1_out,
|
||||
ulong * residual_buffer, ulong * residual_length);
|
||||
|
||||
/*
|
||||
* Name: iucv_reject
|
||||
* Purpose: The reject function refuses a specified message. Between the
|
||||
* time you are notified of a message and the time that you
|
||||
* complete the message, the message may be rejected.
|
||||
* Input: pathid - Path identification number.
|
||||
* msgid - Specifies the message ID.
|
||||
* trgcls - Specifies target class.
|
||||
* Output: NA
|
||||
* Return: Return code from CP IUCV call.
|
||||
*/
|
||||
int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
|
||||
|
||||
/*
|
||||
* Name: iucv_reply
|
||||
* Purpose: This function responds to the two-way messages that you
|
||||
* receive. You must identify completely the message to
|
||||
* which you wish to reply. ie, pathid, msgid, and trgcls.
|
||||
* Input: pathid - Path identification number.
|
||||
* msgid - Specifies the message ID.
|
||||
* trgcls - Specifies target class.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20, Specifies if you want to send priority message.
|
||||
* buffer - Address of reply buffer.
|
||||
* buflen - Length of reply buffer.
|
||||
* Output: residual_buffer - Address of buffer updated by the number
|
||||
* of bytes you have moved.
|
||||
* residual_length - Contains one of the following values:
|
||||
* If the answer buffer is the same length as the reply, this field
|
||||
* contains zero.
|
||||
* If the answer buffer is longer than the reply, this field contains
|
||||
* the number of bytes remaining in the buffer.
|
||||
* If the answer buffer is shorter than the reply, this field contains
|
||||
* a residual count (that is, the number of bytes remianing in the
|
||||
* reply that does not fit into the buffer. In this
|
||||
* case b2f0_result = 5.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer address is NULL.
|
||||
*/
|
||||
int iucv_reply (u16 pathid,
|
||||
u32 msgid,
|
||||
u32 trgcls,
|
||||
int flags1,
|
||||
void *buffer, ulong buflen, ulong * residual_buffer,
|
||||
ulong * residual_length);
|
||||
|
||||
/*
|
||||
* Name: iucv_reply_array
|
||||
* Purpose: This function responds to the two-way messages that you
|
||||
* receive. You must identify completely the message to
|
||||
* which you wish to reply. ie, pathid, msgid, and trgcls.
|
||||
* The array identifies a list of addresses and lengths of
|
||||
* discontiguous buffers that contains the reply data.
|
||||
* Input: pathid - Path identification number
|
||||
* msgid - Specifies the message ID.
|
||||
* trgcls - Specifies target class.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20, Specifies if you want to send priority message.
|
||||
* buffer - Address of array of reply buffers.
|
||||
* buflen - Total length of reply buffers.
|
||||
* Output: residual_buffer - Address of buffer which IUCV is currently working on.
|
||||
* residual_length - Contains one of the following values:
|
||||
* If the answer buffer is the same length as the reply, this field
|
||||
* contains zero.
|
||||
* If the answer buffer is longer than the reply, this field contains
|
||||
* the number of bytes remaining in the buffer.
|
||||
* If the answer buffer is shorter than the reply, this field contains
|
||||
* a residual count (that is, the number of bytes remianing in the
|
||||
* reply that does not fit into the buffer. In this
|
||||
* case b2f0_result = 5.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer address is NULL.
|
||||
*/
|
||||
int iucv_reply_array (u16 pathid,
|
||||
u32 msgid,
|
||||
u32 trgcls,
|
||||
int flags1,
|
||||
iucv_array_t * buffer,
|
||||
ulong buflen, ulong * residual_address,
|
||||
ulong * residual_length);
|
||||
|
||||
/*
|
||||
* Name: iucv_reply_prmmsg
|
||||
* Purpose: This function responds to the two-way messages that you
|
||||
* receive. You must identify completely the message to
|
||||
* which you wish to reply. ie, pathid, msgid, and trgcls.
|
||||
* Prmmsg signifies the data is moved into the
|
||||
* parameter list.
|
||||
* Input: pathid - Path identification number.
|
||||
* msgid - Specifies the message ID.
|
||||
* trgcls - Specifies target class.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20 Specifies if you want to send priority message.
|
||||
* prmmsg - 8-bytes of data to be placed into the parameter.
|
||||
* list.
|
||||
* Output: NA
|
||||
* Return: Return code from CP IUCV call.
|
||||
*/
|
||||
int iucv_reply_prmmsg (u16 pathid,
|
||||
u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
|
||||
|
||||
/*
|
||||
* Name: iucv_resume
|
||||
* Purpose: This function restores communications over a quiesced path
|
||||
* Input: pathid - Path identification number.
|
||||
* user_data - 16-bytes of user data.
|
||||
* Output: NA
|
||||
* Return: Return code from CP IUCV call.
|
||||
*/
|
||||
int iucv_resume (u16 pathid, uchar user_data[16]);
|
||||
|
||||
/*
|
||||
* Name: iucv_send
|
||||
* Purpose: This function transmits data to another application.
|
||||
* Data to be transmitted is in a buffer and this is a
|
||||
* one-way message and the receiver will not reply to the
|
||||
* message.
|
||||
* Input: pathid - Path identification number.
|
||||
* trgcls - Specifies target class.
|
||||
* srccls - Specifies the source message class.
|
||||
* msgtag - Specifies a tag to be associated with the message.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20 Specifies if you want to send priority message.
|
||||
* buffer - Address of send buffer.
|
||||
* buflen - Length of send buffer.
|
||||
* Output: msgid - Specifies the message ID.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer address is NULL.
|
||||
*/
|
||||
int iucv_send (u16 pathid,
|
||||
u32 * msgid,
|
||||
u32 trgcls,
|
||||
u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
|
||||
|
||||
/*
|
||||
* Name: iucv_send_array
|
||||
* Purpose: This function transmits data to another application.
|
||||
* The contents of buffer is the address of the array of
|
||||
* addresses and lengths of discontiguous buffers that hold
|
||||
* the message text. This is a one-way message and the
|
||||
* receiver will not reply to the message.
|
||||
* Input: pathid - Path identification number.
|
||||
* trgcls - Specifies target class.
|
||||
* srccls - Specifies the source message class.
|
||||
* msgtag - Specifies a tag to be associated witht the message.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- specifies if you want to send priority message.
|
||||
* buffer - Address of array of send buffers.
|
||||
* buflen - Total length of send buffers.
|
||||
* Output: msgid - Specifies the message ID.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer address is NULL.
|
||||
*/
|
||||
int iucv_send_array (u16 pathid,
|
||||
u32 * msgid,
|
||||
u32 trgcls,
|
||||
u32 srccls,
|
||||
u32 msgtag,
|
||||
int flags1, iucv_array_t * buffer, ulong buflen);
|
||||
|
||||
/*
|
||||
* Name: iucv_send_prmmsg
|
||||
* Purpose: This function transmits data to another application.
|
||||
* Prmmsg specifies that the 8-bytes of data are to be moved
|
||||
* into the parameter list. This is a one-way message and the
|
||||
* receiver will not reply to the message.
|
||||
* Input: pathid - Path identification number.
|
||||
* trgcls - Specifies target class.
|
||||
* srccls - Specifies the source message class.
|
||||
* msgtag - Specifies a tag to be associated with the message.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20 specifies if you want to send priority message.
|
||||
* prmmsg - 8-bytes of data to be placed into parameter list.
|
||||
* Output: msgid - Specifies the message ID.
|
||||
* Return: Return code from CP IUCV call.
|
||||
*/
|
||||
int iucv_send_prmmsg (u16 pathid,
|
||||
u32 * msgid,
|
||||
u32 trgcls,
|
||||
u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
|
||||
|
||||
/*
|
||||
* Name: iucv_send2way
|
||||
* Purpose: This function transmits data to another application.
|
||||
* Data to be transmitted is in a buffer. The receiver
|
||||
* of the send is expected to reply to the message and
|
||||
* a buffer is provided into which IUCV moves the reply
|
||||
* to this message.
|
||||
* Input: pathid - Path identification number.
|
||||
* trgcls - Specifies target class.
|
||||
* srccls - Specifies the source message class.
|
||||
* msgtag - Specifies a tag associated with the message.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20 Specifies if you want to send priority message.
|
||||
* buffer - Address of send buffer.
|
||||
* buflen - Length of send buffer.
|
||||
* ansbuf - Address of buffer into which IUCV moves the reply of
|
||||
* this message.
|
||||
* anslen - Address of length of buffer.
|
||||
* Output: msgid - Specifies the message ID.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer or ansbuf address is NULL.
|
||||
*/
|
||||
int iucv_send2way (u16 pathid,
|
||||
u32 * msgid,
|
||||
u32 trgcls,
|
||||
u32 srccls,
|
||||
u32 msgtag,
|
||||
int flags1,
|
||||
void *buffer, ulong buflen, void *ansbuf, ulong anslen);
|
||||
|
||||
/*
|
||||
* Name: iucv_send2way_array
|
||||
* Purpose: This function transmits data to another application.
|
||||
* The contents of buffer is the address of the array of
|
||||
* addresses and lengths of discontiguous buffers that hold
|
||||
* the message text. The receiver of the send is expected to
|
||||
* reply to the message and a buffer is provided into which
|
||||
* IUCV moves the reply to this message.
|
||||
* Input: pathid - Path identification number.
|
||||
* trgcls - Specifies target class.
|
||||
* srccls - Specifies the source message class.
|
||||
* msgtag - Specifies a tag to be associated with the message.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20 Specifies if you want to send priority message.
|
||||
* buffer - Sddress of array of send buffers.
|
||||
* buflen - Total length of send buffers.
|
||||
* ansbuf - Address of array of buffer into which IUCV moves the reply
|
||||
* of this message.
|
||||
* anslen - Address of length reply buffers.
|
||||
* Output: msgid - Specifies the message ID.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer address is NULL.
|
||||
*/
|
||||
int iucv_send2way_array (u16 pathid,
|
||||
u32 * msgid,
|
||||
u32 trgcls,
|
||||
u32 srccls,
|
||||
u32 msgtag,
|
||||
int flags1,
|
||||
iucv_array_t * buffer,
|
||||
ulong buflen, iucv_array_t * ansbuf, ulong anslen);
|
||||
|
||||
/*
|
||||
* Name: iucv_send2way_prmmsg
|
||||
* Purpose: This function transmits data to another application.
|
||||
* Prmmsg specifies that the 8-bytes of data are to be moved
|
||||
* into the parameter list. This is a two-way message and the
|
||||
* receiver of the message is expected to reply. A buffer
|
||||
* is provided into which IUCV moves the reply to this
|
||||
* message.
|
||||
* Input: pathid - Rath identification number.
|
||||
* trgcls - Specifies target class.
|
||||
* srccls - Specifies the source message class.
|
||||
* msgtag - Specifies a tag to be associated with the message.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20 Specifies if you want to send priority message.
|
||||
* prmmsg - 8-bytes of data to be placed in parameter list.
|
||||
* ansbuf - Address of buffer into which IUCV moves the reply of
|
||||
* this message.
|
||||
* anslen - Address of length of buffer.
|
||||
* Output: msgid - Specifies the message ID.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Buffer address is NULL.
|
||||
*/
|
||||
int iucv_send2way_prmmsg (u16 pathid,
|
||||
u32 * msgid,
|
||||
u32 trgcls,
|
||||
u32 srccls,
|
||||
u32 msgtag,
|
||||
ulong flags1,
|
||||
uchar prmmsg[8], void *ansbuf, ulong anslen);
|
||||
|
||||
/*
|
||||
* Name: iucv_send2way_prmmsg_array
|
||||
* Purpose: This function transmits data to another application.
|
||||
* Prmmsg specifies that the 8-bytes of data are to be moved
|
||||
* into the parameter list. This is a two-way message and the
|
||||
* receiver of the message is expected to reply. A buffer
|
||||
* is provided into which IUCV moves the reply to this
|
||||
* message. The contents of ansbuf is the address of the
|
||||
* array of addresses and lengths of discontiguous buffers
|
||||
* that contain the reply.
|
||||
* Input: pathid - Path identification number.
|
||||
* trgcls - Specifies target class.
|
||||
* srccls - Specifies the source message class.
|
||||
* msgtag - Specifies a tag to be associated with the message.
|
||||
* flags1 - Option for path.
|
||||
* IPPRTY- 0x20 specifies if you want to send priority message.
|
||||
* prmmsg - 8-bytes of data to be placed into the parameter list.
|
||||
* ansbuf - Address of array of buffer into which IUCV moves the reply
|
||||
* of this message.
|
||||
* anslen - Address of length of reply buffers.
|
||||
* Output: msgid - Specifies the message ID.
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Ansbuf address is NULL.
|
||||
*/
|
||||
int iucv_send2way_prmmsg_array (u16 pathid,
|
||||
u32 * msgid,
|
||||
u32 trgcls,
|
||||
u32 srccls,
|
||||
u32 msgtag,
|
||||
int flags1,
|
||||
uchar prmmsg[8],
|
||||
iucv_array_t * ansbuf, ulong anslen);
|
||||
|
||||
/*
|
||||
* Name: iucv_setmask
|
||||
* Purpose: This function enables or disables the following IUCV
|
||||
* external interruptions: Nonpriority and priority message
|
||||
* interrupts, nonpriority and priority reply interrupts.
|
||||
* Input: SetMaskFlag - options for interrupts
|
||||
* 0x80 - Nonpriority_MessagePendingInterruptsFlag
|
||||
* 0x40 - Priority_MessagePendingInterruptsFlag
|
||||
* 0x20 - Nonpriority_MessageCompletionInterruptsFlag
|
||||
* 0x10 - Priority_MessageCompletionInterruptsFlag
|
||||
* 0x08 - IUCVControlInterruptsFlag
|
||||
* Output: NA
|
||||
* Return: Return code from CP IUCV call.
|
||||
*/
|
||||
int iucv_setmask (int SetMaskFlag);
|
||||
|
||||
/*
|
||||
* Name: iucv_sever
|
||||
* Purpose: This function terminates an IUCV path.
|
||||
* Input: pathid - Path identification number.
|
||||
* user_data - 16-bytes of user data.
|
||||
* Output: NA
|
||||
* Return: Return code from CP IUCV call.
|
||||
* (-EINVAL) - Interal error, wild pointer.
|
||||
*/
|
||||
int iucv_sever (u16 pathid, uchar user_data[16]);
|
2347
drivers/s390/net/lcs.c
Normale Datei
2347
drivers/s390/net/lcs.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
321
drivers/s390/net/lcs.h
Normale Datei
321
drivers/s390/net/lcs.h
Normale Datei
@@ -0,0 +1,321 @@
|
||||
/*lcs.h*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <asm/ccwdev.h>
|
||||
|
||||
#define VERSION_LCS_H "$Revision: 1.19 $"
|
||||
|
||||
#define LCS_DBF_TEXT(level, name, text) \
|
||||
do { \
|
||||
debug_text_event(lcs_dbf_##name, level, text); \
|
||||
} while (0)
|
||||
|
||||
#define LCS_DBF_HEX(level,name,addr,len) \
|
||||
do { \
|
||||
debug_event(lcs_dbf_##name,level,(void*)(addr),len); \
|
||||
} while (0)
|
||||
|
||||
#define LCS_DBF_TEXT_(level,name,text...) \
|
||||
do { \
|
||||
sprintf(debug_buffer, text); \
|
||||
debug_text_event(lcs_dbf_##name,level, debug_buffer);\
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* some more definitions for debug or output stuff
|
||||
*/
|
||||
#define PRINTK_HEADER " lcs: "
|
||||
|
||||
/**
|
||||
* sysfs related stuff
|
||||
*/
|
||||
#define CARD_FROM_DEV(cdev) \
|
||||
(struct lcs_card *) \
|
||||
((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data;
|
||||
/**
|
||||
* CCW commands used in this driver
|
||||
*/
|
||||
#define LCS_CCW_WRITE 0x01
|
||||
#define LCS_CCW_READ 0x02
|
||||
#define LCS_CCW_TRANSFER 0x08
|
||||
|
||||
/**
|
||||
* LCS device status primitives
|
||||
*/
|
||||
#define LCS_CMD_STARTLAN 0x01
|
||||
#define LCS_CMD_STOPLAN 0x02
|
||||
#define LCS_CMD_LANSTAT 0x04
|
||||
#define LCS_CMD_STARTUP 0x07
|
||||
#define LCS_CMD_SHUTDOWN 0x08
|
||||
#define LCS_CMD_QIPASSIST 0xb2
|
||||
#define LCS_CMD_SETIPM 0xb4
|
||||
#define LCS_CMD_DELIPM 0xb5
|
||||
|
||||
#define LCS_INITIATOR_TCPIP 0x00
|
||||
#define LCS_INITIATOR_LGW 0x01
|
||||
#define LCS_STD_CMD_SIZE 16
|
||||
#define LCS_MULTICAST_CMD_SIZE 404
|
||||
|
||||
/**
|
||||
* LCS IPASSIST MASKS,only used when multicast is switched on
|
||||
*/
|
||||
/* Not supported by LCS */
|
||||
#define LCS_IPASS_ARP_PROCESSING 0x0001
|
||||
#define LCS_IPASS_IN_CHECKSUM_SUPPORT 0x0002
|
||||
#define LCS_IPASS_OUT_CHECKSUM_SUPPORT 0x0004
|
||||
#define LCS_IPASS_IP_FRAG_REASSEMBLY 0x0008
|
||||
#define LCS_IPASS_IP_FILTERING 0x0010
|
||||
/* Supported by lcs 3172 */
|
||||
#define LCS_IPASS_IPV6_SUPPORT 0x0020
|
||||
#define LCS_IPASS_MULTICAST_SUPPORT 0x0040
|
||||
|
||||
/**
|
||||
* LCS sense byte definitions
|
||||
*/
|
||||
#define LCS_SENSE_INTERFACE_DISCONNECT 0x01
|
||||
#define LCS_SENSE_EQUIPMENT_CHECK 0x10
|
||||
#define LCS_SENSE_BUS_OUT_CHECK 0x20
|
||||
#define LCS_SENSE_INTERVENTION_REQUIRED 0x40
|
||||
#define LCS_SENSE_CMD_REJECT 0x80
|
||||
#define LCS_SENSE_RESETTING_EVENT 0x0080
|
||||
#define LCS_SENSE_DEVICE_ONLINE 0x0020
|
||||
|
||||
/**
|
||||
* LCS packet type definitions
|
||||
*/
|
||||
#define LCS_FRAME_TYPE_CONTROL 0
|
||||
#define LCS_FRAME_TYPE_ENET 1
|
||||
#define LCS_FRAME_TYPE_TR 2
|
||||
#define LCS_FRAME_TYPE_FDDI 7
|
||||
#define LCS_FRAME_TYPE_AUTO -1
|
||||
|
||||
/**
|
||||
* some more definitions,we will sort them later
|
||||
*/
|
||||
#define LCS_ILLEGAL_OFFSET 0xffff
|
||||
#define LCS_IOBUFFERSIZE 0x5000
|
||||
#define LCS_NUM_BUFFS 8 /* needs to be power of 2 */
|
||||
#define LCS_MAC_LENGTH 6
|
||||
#define LCS_INVALID_PORT_NO -1
|
||||
#define LCS_LANCMD_TIMEOUT_DEFAULT 5
|
||||
|
||||
/**
|
||||
* Multicast state
|
||||
*/
|
||||
#define LCS_IPM_STATE_SET_REQUIRED 0
|
||||
#define LCS_IPM_STATE_DEL_REQUIRED 1
|
||||
#define LCS_IPM_STATE_ON_CARD 2
|
||||
|
||||
/**
|
||||
* LCS IP Assist declarations
|
||||
* seems to be only used for multicast
|
||||
*/
|
||||
#define LCS_IPASS_ARP_PROCESSING 0x0001
|
||||
#define LCS_IPASS_INBOUND_CSUM_SUPP 0x0002
|
||||
#define LCS_IPASS_OUTBOUND_CSUM_SUPP 0x0004
|
||||
#define LCS_IPASS_IP_FRAG_REASSEMBLY 0x0008
|
||||
#define LCS_IPASS_IP_FILTERING 0x0010
|
||||
#define LCS_IPASS_IPV6_SUPPORT 0x0020
|
||||
#define LCS_IPASS_MULTICAST_SUPPORT 0x0040
|
||||
|
||||
/**
|
||||
* LCS Buffer states
|
||||
*/
|
||||
enum lcs_buffer_states {
|
||||
BUF_STATE_EMPTY, /* buffer is empty */
|
||||
BUF_STATE_LOCKED, /* buffer is locked, don't touch */
|
||||
BUF_STATE_READY, /* buffer is ready for read/write */
|
||||
BUF_STATE_PROCESSED,
|
||||
};
|
||||
|
||||
/**
|
||||
* LCS Channel State Machine declarations
|
||||
*/
|
||||
enum lcs_channel_states {
|
||||
CH_STATE_INIT,
|
||||
CH_STATE_HALTED,
|
||||
CH_STATE_STOPPED,
|
||||
CH_STATE_RUNNING,
|
||||
CH_STATE_SUSPENDED,
|
||||
CH_STATE_CLEARED,
|
||||
};
|
||||
|
||||
/**
|
||||
* LCS device state machine
|
||||
*/
|
||||
enum lcs_dev_states {
|
||||
DEV_STATE_DOWN,
|
||||
DEV_STATE_UP,
|
||||
DEV_STATE_RECOVER,
|
||||
};
|
||||
|
||||
enum lcs_threads {
|
||||
LCS_SET_MC_THREAD = 1,
|
||||
LCS_STARTLAN_THREAD = 2,
|
||||
LCS_STOPLAN_THREAD = 4,
|
||||
LCS_STARTUP_THREAD = 8,
|
||||
};
|
||||
/**
|
||||
* LCS struct declarations
|
||||
*/
|
||||
struct lcs_header {
|
||||
__u16 offset;
|
||||
__u8 type;
|
||||
__u8 slot;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct lcs_ip_mac_pair {
|
||||
__u32 ip_addr;
|
||||
__u8 mac_addr[LCS_MAC_LENGTH];
|
||||
__u8 reserved[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct lcs_ipm_list {
|
||||
struct list_head list;
|
||||
struct lcs_ip_mac_pair ipm;
|
||||
__u8 ipm_state;
|
||||
};
|
||||
|
||||
struct lcs_cmd {
|
||||
__u16 offset;
|
||||
__u8 type;
|
||||
__u8 slot;
|
||||
__u8 cmd_code;
|
||||
__u8 initiator;
|
||||
__u16 sequence_no;
|
||||
__u16 return_code;
|
||||
union {
|
||||
struct {
|
||||
__u8 lan_type;
|
||||
__u8 portno;
|
||||
__u16 parameter_count;
|
||||
__u8 operator_flags[3];
|
||||
__u8 reserved[3];
|
||||
} lcs_std_cmd;
|
||||
struct {
|
||||
__u16 unused1;
|
||||
__u16 buff_size;
|
||||
__u8 unused2[6];
|
||||
} lcs_startup;
|
||||
struct {
|
||||
__u8 lan_type;
|
||||
__u8 portno;
|
||||
__u8 unused[10];
|
||||
__u8 mac_addr[LCS_MAC_LENGTH];
|
||||
__u32 num_packets_deblocked;
|
||||
__u32 num_packets_blocked;
|
||||
__u32 num_packets_tx_on_lan;
|
||||
__u32 num_tx_errors_detected;
|
||||
__u32 num_tx_packets_disgarded;
|
||||
__u32 num_packets_rx_from_lan;
|
||||
__u32 num_rx_errors_detected;
|
||||
__u32 num_rx_discarded_nobuffs_avail;
|
||||
__u32 num_rx_packets_too_large;
|
||||
} lcs_lanstat_cmd;
|
||||
#ifdef CONFIG_IP_MULTICAST
|
||||
struct {
|
||||
__u8 lan_type;
|
||||
__u8 portno;
|
||||
__u16 num_ip_pairs;
|
||||
__u16 ip_assists_supported;
|
||||
__u16 ip_assists_enabled;
|
||||
__u16 version;
|
||||
struct {
|
||||
struct lcs_ip_mac_pair
|
||||
ip_mac_pair[32];
|
||||
__u32 response_data;
|
||||
} lcs_ipass_ctlmsg __attribute ((packed));
|
||||
} lcs_qipassist __attribute__ ((packed));
|
||||
#endif /*CONFIG_IP_MULTICAST */
|
||||
} cmd __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/**
|
||||
* Forward declarations.
|
||||
*/
|
||||
struct lcs_card;
|
||||
struct lcs_channel;
|
||||
|
||||
/**
|
||||
* Definition of an lcs buffer.
|
||||
*/
|
||||
struct lcs_buffer {
|
||||
enum lcs_buffer_states state;
|
||||
void *data;
|
||||
int count;
|
||||
/* Callback for completion notification. */
|
||||
void (*callback)(struct lcs_channel *, struct lcs_buffer *);
|
||||
};
|
||||
|
||||
struct lcs_reply {
|
||||
struct list_head list;
|
||||
__u16 sequence_no;
|
||||
atomic_t refcnt;
|
||||
/* Callback for completion notification. */
|
||||
void (*callback)(struct lcs_card *, struct lcs_cmd *);
|
||||
wait_queue_head_t wait_q;
|
||||
struct lcs_card *card;
|
||||
int received;
|
||||
int rc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Definition of an lcs channel
|
||||
*/
|
||||
struct lcs_channel {
|
||||
enum lcs_channel_states state;
|
||||
struct ccw_device *ccwdev;
|
||||
struct ccw1 ccws[LCS_NUM_BUFFS + 1];
|
||||
wait_queue_head_t wait_q;
|
||||
struct tasklet_struct irq_tasklet;
|
||||
struct lcs_buffer iob[LCS_NUM_BUFFS];
|
||||
int io_idx;
|
||||
int buf_idx;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* definition of the lcs card
|
||||
*/
|
||||
struct lcs_card {
|
||||
spinlock_t lock;
|
||||
spinlock_t ipm_lock;
|
||||
enum lcs_dev_states state;
|
||||
struct net_device *dev;
|
||||
struct net_device_stats stats;
|
||||
unsigned short (*lan_type_trans)(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
struct lcs_channel read;
|
||||
struct lcs_channel write;
|
||||
struct lcs_buffer *tx_buffer;
|
||||
int tx_emitted;
|
||||
struct list_head lancmd_waiters;
|
||||
int lancmd_timeout;
|
||||
|
||||
struct work_struct kernel_thread_starter;
|
||||
spinlock_t mask_lock;
|
||||
unsigned long thread_start_mask;
|
||||
unsigned long thread_running_mask;
|
||||
unsigned long thread_allowed_mask;
|
||||
wait_queue_head_t wait_q;
|
||||
|
||||
#ifdef CONFIG_IP_MULTICAST
|
||||
struct list_head ipm_list;
|
||||
#endif
|
||||
__u8 mac[LCS_MAC_LENGTH];
|
||||
__u16 ip_assists_supported;
|
||||
__u16 ip_assists_enabled;
|
||||
__s8 lan_type;
|
||||
__u32 pkt_seq;
|
||||
__u16 sequence_no;
|
||||
__s16 portno;
|
||||
/* Some info copied from probeinfo */
|
||||
u8 device_forced;
|
||||
u8 max_port_no;
|
||||
u8 hint_port_no;
|
||||
s16 port_protocol_no;
|
||||
} __attribute__ ((aligned(8)));
|
||||
|
2149
drivers/s390/net/netiucv.c
Normale Datei
2149
drivers/s390/net/netiucv.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
1162
drivers/s390/net/qeth.h
Normale Datei
1162
drivers/s390/net/qeth.h
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
643
drivers/s390/net/qeth_eddp.c
Normale Datei
643
drivers/s390/net/qeth_eddp.c
Normale Datei
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
*
|
||||
* linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.11 $)
|
||||
*
|
||||
* Enhanced Device Driver Packing (EDDP) support for the qeth driver.
|
||||
*
|
||||
* Copyright 2004 IBM Corporation
|
||||
*
|
||||
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
|
||||
*
|
||||
* $Revision: 1.11 $ $Date: 2005/03/24 09:04:18 $
|
||||
*
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "qeth.h"
|
||||
#include "qeth_mpc.h"
|
||||
#include "qeth_eddp.h"
|
||||
|
||||
int
|
||||
qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue,
|
||||
struct qeth_eddp_context *ctx)
|
||||
{
|
||||
int index = queue->next_buf_to_fill;
|
||||
int elements_needed = ctx->num_elements;
|
||||
int elements_in_buffer;
|
||||
int skbs_in_buffer;
|
||||
int buffers_needed = 0;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpcbfc");
|
||||
while(elements_needed > 0) {
|
||||
buffers_needed++;
|
||||
if (atomic_read(&queue->bufs[index].state) !=
|
||||
QETH_QDIO_BUF_EMPTY)
|
||||
return -EBUSY;
|
||||
|
||||
elements_in_buffer = QETH_MAX_BUFFER_ELEMENTS(queue->card) -
|
||||
queue->bufs[index].next_element_to_fill;
|
||||
skbs_in_buffer = elements_in_buffer / ctx->elements_per_skb;
|
||||
elements_needed -= skbs_in_buffer * ctx->elements_per_skb;
|
||||
index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
|
||||
}
|
||||
return buffers_needed;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qeth_eddp_free_context(struct qeth_eddp_context *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpfctx");
|
||||
for (i = 0; i < ctx->num_pages; ++i)
|
||||
free_page((unsigned long)ctx->pages[i]);
|
||||
kfree(ctx->pages);
|
||||
if (ctx->elements != NULL)
|
||||
kfree(ctx->elements);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
qeth_eddp_get_context(struct qeth_eddp_context *ctx)
|
||||
{
|
||||
atomic_inc(&ctx->refcnt);
|
||||
}
|
||||
|
||||
void
|
||||
qeth_eddp_put_context(struct qeth_eddp_context *ctx)
|
||||
{
|
||||
if (atomic_dec_return(&ctx->refcnt) == 0)
|
||||
qeth_eddp_free_context(ctx);
|
||||
}
|
||||
|
||||
void
|
||||
qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
|
||||
{
|
||||
struct qeth_eddp_context_reference *ref;
|
||||
|
||||
QETH_DBF_TEXT(trace, 6, "eddprctx");
|
||||
while (!list_empty(&buf->ctx_list)){
|
||||
ref = list_entry(buf->ctx_list.next,
|
||||
struct qeth_eddp_context_reference, list);
|
||||
qeth_eddp_put_context(ref->ctx);
|
||||
list_del(&ref->list);
|
||||
kfree(ref);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
|
||||
struct qeth_eddp_context *ctx)
|
||||
{
|
||||
struct qeth_eddp_context_reference *ref;
|
||||
|
||||
QETH_DBF_TEXT(trace, 6, "eddprfcx");
|
||||
ref = kmalloc(sizeof(struct qeth_eddp_context_reference), GFP_ATOMIC);
|
||||
if (ref == NULL)
|
||||
return -ENOMEM;
|
||||
qeth_eddp_get_context(ctx);
|
||||
ref->ctx = ctx;
|
||||
list_add_tail(&ref->list, &buf->ctx_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
|
||||
struct qeth_eddp_context *ctx,
|
||||
int index)
|
||||
{
|
||||
struct qeth_qdio_out_buffer *buf = NULL;
|
||||
struct qdio_buffer *buffer;
|
||||
int elements = ctx->num_elements;
|
||||
int element = 0;
|
||||
int flush_cnt = 0;
|
||||
int must_refcnt = 1;
|
||||
int i;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpfibu");
|
||||
while (elements > 0) {
|
||||
buf = &queue->bufs[index];
|
||||
if (atomic_read(&buf->state) != QETH_QDIO_BUF_EMPTY){
|
||||
/* normally this should not happen since we checked for
|
||||
* available elements in qeth_check_elements_for_context
|
||||
*/
|
||||
if (element == 0)
|
||||
return -EBUSY;
|
||||
else {
|
||||
PRINT_WARN("could only partially fill eddp "
|
||||
"buffer!\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* check if the whole next skb fits into current buffer */
|
||||
if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
|
||||
buf->next_element_to_fill)
|
||||
< ctx->elements_per_skb){
|
||||
/* no -> go to next buffer */
|
||||
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
|
||||
index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
|
||||
flush_cnt++;
|
||||
/* new buffer, so we have to add ctx to buffer'ctx_list
|
||||
* and increment ctx's refcnt */
|
||||
must_refcnt = 1;
|
||||
continue;
|
||||
}
|
||||
if (must_refcnt){
|
||||
must_refcnt = 0;
|
||||
if (qeth_eddp_buf_ref_context(buf, ctx)){
|
||||
PRINT_WARN("no memory to create eddp context "
|
||||
"reference\n");
|
||||
goto out_check;
|
||||
}
|
||||
}
|
||||
buffer = buf->buffer;
|
||||
/* fill one skb into buffer */
|
||||
for (i = 0; i < ctx->elements_per_skb; ++i){
|
||||
buffer->element[buf->next_element_to_fill].addr =
|
||||
ctx->elements[element].addr;
|
||||
buffer->element[buf->next_element_to_fill].length =
|
||||
ctx->elements[element].length;
|
||||
buffer->element[buf->next_element_to_fill].flags =
|
||||
ctx->elements[element].flags;
|
||||
buf->next_element_to_fill++;
|
||||
element++;
|
||||
elements--;
|
||||
}
|
||||
}
|
||||
out_check:
|
||||
if (!queue->do_pack) {
|
||||
QETH_DBF_TEXT(trace, 6, "fillbfnp");
|
||||
/* set state to PRIMED -> will be flushed */
|
||||
if (buf->next_element_to_fill > 0){
|
||||
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
|
||||
flush_cnt++;
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_QETH_PERF_STATS
|
||||
queue->card->perf_stats.skbs_sent_pack++;
|
||||
#endif
|
||||
QETH_DBF_TEXT(trace, 6, "fillbfpa");
|
||||
if (buf->next_element_to_fill >=
|
||||
QETH_MAX_BUFFER_ELEMENTS(queue->card)) {
|
||||
/*
|
||||
* packed buffer if full -> set state PRIMED
|
||||
* -> will be flushed
|
||||
*/
|
||||
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
|
||||
flush_cnt++;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return flush_cnt;
|
||||
}
|
||||
|
||||
static inline int
|
||||
qeth_get_skb_data_len(struct sk_buff *skb)
|
||||
{
|
||||
int len = skb->len;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i)
|
||||
len -= skb_shinfo(skb)->frags[i].size;
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
|
||||
struct qeth_eddp_data *eddp)
|
||||
{
|
||||
u8 *page;
|
||||
int page_remainder;
|
||||
int page_offset;
|
||||
int hdr_len;
|
||||
struct qeth_eddp_element *element;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpcrsh");
|
||||
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
|
||||
page_offset = ctx->offset % PAGE_SIZE;
|
||||
element = &ctx->elements[ctx->num_elements];
|
||||
hdr_len = eddp->nhl + eddp->thl;
|
||||
/* FIXME: layer2 and VLAN !!! */
|
||||
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
|
||||
hdr_len += ETH_HLEN;
|
||||
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
|
||||
hdr_len += VLAN_HLEN;
|
||||
/* does complete header fit in current page ? */
|
||||
page_remainder = PAGE_SIZE - page_offset;
|
||||
if (page_remainder < (sizeof(struct qeth_hdr) + hdr_len)){
|
||||
/* no -> go to start of next page */
|
||||
ctx->offset += page_remainder;
|
||||
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
|
||||
page_offset = 0;
|
||||
}
|
||||
memcpy(page + page_offset, &eddp->qh, sizeof(struct qeth_hdr));
|
||||
element->addr = page + page_offset;
|
||||
element->length = sizeof(struct qeth_hdr);
|
||||
ctx->offset += sizeof(struct qeth_hdr);
|
||||
page_offset += sizeof(struct qeth_hdr);
|
||||
/* add mac header (?) */
|
||||
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
|
||||
memcpy(page + page_offset, &eddp->mac, ETH_HLEN);
|
||||
element->length += ETH_HLEN;
|
||||
ctx->offset += ETH_HLEN;
|
||||
page_offset += ETH_HLEN;
|
||||
}
|
||||
/* add VLAN tag */
|
||||
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)){
|
||||
memcpy(page + page_offset, &eddp->vlan, VLAN_HLEN);
|
||||
element->length += VLAN_HLEN;
|
||||
ctx->offset += VLAN_HLEN;
|
||||
page_offset += VLAN_HLEN;
|
||||
}
|
||||
/* add network header */
|
||||
memcpy(page + page_offset, (u8 *)&eddp->nh, eddp->nhl);
|
||||
element->length += eddp->nhl;
|
||||
eddp->nh_in_ctx = page + page_offset;
|
||||
ctx->offset += eddp->nhl;
|
||||
page_offset += eddp->nhl;
|
||||
/* add transport header */
|
||||
memcpy(page + page_offset, (u8 *)&eddp->th, eddp->thl);
|
||||
element->length += eddp->thl;
|
||||
eddp->th_in_ctx = page + page_offset;
|
||||
ctx->offset += eddp->thl;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
|
||||
u32 *hcsum)
|
||||
{
|
||||
struct skb_frag_struct *frag;
|
||||
int left_in_frag;
|
||||
int copy_len;
|
||||
u8 *src;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpcdtc");
|
||||
if (skb_shinfo(eddp->skb)->nr_frags == 0) {
|
||||
memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
|
||||
*hcsum = csum_partial(eddp->skb->data + eddp->skb_offset, len,
|
||||
*hcsum);
|
||||
eddp->skb_offset += len;
|
||||
} else {
|
||||
while (len > 0) {
|
||||
if (eddp->frag < 0) {
|
||||
/* we're in skb->data */
|
||||
left_in_frag = qeth_get_skb_data_len(eddp->skb)
|
||||
- eddp->skb_offset;
|
||||
src = eddp->skb->data + eddp->skb_offset;
|
||||
} else {
|
||||
frag = &skb_shinfo(eddp->skb)->
|
||||
frags[eddp->frag];
|
||||
left_in_frag = frag->size - eddp->frag_offset;
|
||||
src = (u8 *)(
|
||||
(page_to_pfn(frag->page) << PAGE_SHIFT)+
|
||||
frag->page_offset + eddp->frag_offset);
|
||||
}
|
||||
if (left_in_frag <= 0) {
|
||||
eddp->frag++;
|
||||
eddp->frag_offset = 0;
|
||||
continue;
|
||||
}
|
||||
copy_len = min(left_in_frag, len);
|
||||
memcpy(dst, src, copy_len);
|
||||
*hcsum = csum_partial(src, copy_len, *hcsum);
|
||||
dst += copy_len;
|
||||
eddp->frag_offset += copy_len;
|
||||
eddp->skb_offset += copy_len;
|
||||
len -= copy_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
|
||||
struct qeth_eddp_data *eddp, int data_len,
|
||||
u32 hcsum)
|
||||
{
|
||||
u8 *page;
|
||||
int page_remainder;
|
||||
int page_offset;
|
||||
struct qeth_eddp_element *element;
|
||||
int first_lap = 1;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpcsdt");
|
||||
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
|
||||
page_offset = ctx->offset % PAGE_SIZE;
|
||||
element = &ctx->elements[ctx->num_elements];
|
||||
while (data_len){
|
||||
page_remainder = PAGE_SIZE - page_offset;
|
||||
if (page_remainder < data_len){
|
||||
qeth_eddp_copy_data_tcp(page + page_offset, eddp,
|
||||
page_remainder, &hcsum);
|
||||
element->length += page_remainder;
|
||||
if (first_lap)
|
||||
element->flags = SBAL_FLAGS_FIRST_FRAG;
|
||||
else
|
||||
element->flags = SBAL_FLAGS_MIDDLE_FRAG;
|
||||
ctx->num_elements++;
|
||||
element++;
|
||||
data_len -= page_remainder;
|
||||
ctx->offset += page_remainder;
|
||||
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
|
||||
page_offset = 0;
|
||||
element->addr = page + page_offset;
|
||||
} else {
|
||||
qeth_eddp_copy_data_tcp(page + page_offset, eddp,
|
||||
data_len, &hcsum);
|
||||
element->length += data_len;
|
||||
if (!first_lap)
|
||||
element->flags = SBAL_FLAGS_LAST_FRAG;
|
||||
ctx->num_elements++;
|
||||
ctx->offset += data_len;
|
||||
data_len = 0;
|
||||
}
|
||||
first_lap = 0;
|
||||
}
|
||||
((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
|
||||
{
|
||||
u32 phcsum; /* pseudo header checksum */
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpckt4");
|
||||
eddp->th.tcp.h.check = 0;
|
||||
/* compute pseudo header checksum */
|
||||
phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr,
|
||||
eddp->thl + data_len, IPPROTO_TCP, 0);
|
||||
/* compute checksum of tcp header */
|
||||
return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
|
||||
{
|
||||
u32 proto;
|
||||
u32 phcsum; /* pseudo header checksum */
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpckt6");
|
||||
eddp->th.tcp.h.check = 0;
|
||||
/* compute pseudo header checksum */
|
||||
phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr,
|
||||
sizeof(struct in6_addr), 0);
|
||||
phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr,
|
||||
sizeof(struct in6_addr), phcsum);
|
||||
proto = htonl(IPPROTO_TCP);
|
||||
phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum);
|
||||
return phcsum;
|
||||
}
|
||||
|
||||
static inline struct qeth_eddp_data *
|
||||
qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
|
||||
{
|
||||
struct qeth_eddp_data *eddp;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpcrda");
|
||||
eddp = kmalloc(sizeof(struct qeth_eddp_data), GFP_ATOMIC);
|
||||
if (eddp){
|
||||
memset(eddp, 0, sizeof(struct qeth_eddp_data));
|
||||
eddp->nhl = nhl;
|
||||
eddp->thl = thl;
|
||||
memcpy(&eddp->qh, qh, sizeof(struct qeth_hdr));
|
||||
memcpy(&eddp->nh, nh, nhl);
|
||||
memcpy(&eddp->th, th, thl);
|
||||
eddp->frag = -1; /* initially we're in skb->data */
|
||||
}
|
||||
return eddp;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
|
||||
struct qeth_eddp_data *eddp)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
int data_len;
|
||||
u32 hcsum;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpftcp");
|
||||
eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
|
||||
tcph = eddp->skb->h.th;
|
||||
while (eddp->skb_offset < eddp->skb->len) {
|
||||
data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
|
||||
(int)(eddp->skb->len - eddp->skb_offset));
|
||||
/* prepare qdio hdr */
|
||||
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
|
||||
eddp->qh.hdr.l2.pkt_length = data_len + ETH_HLEN +
|
||||
eddp->nhl + eddp->thl -
|
||||
sizeof(struct qeth_hdr);
|
||||
#ifdef CONFIG_QETH_VLAN
|
||||
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
|
||||
eddp->qh.hdr.l2.pkt_length += VLAN_HLEN;
|
||||
#endif /* CONFIG_QETH_VLAN */
|
||||
} else
|
||||
eddp->qh.hdr.l3.length = data_len + eddp->nhl +
|
||||
eddp->thl;
|
||||
/* prepare ip hdr */
|
||||
if (eddp->skb->protocol == ETH_P_IP){
|
||||
eddp->nh.ip4.h.tot_len = data_len + eddp->nhl +
|
||||
eddp->thl;
|
||||
eddp->nh.ip4.h.check = 0;
|
||||
eddp->nh.ip4.h.check =
|
||||
ip_fast_csum((u8 *)&eddp->nh.ip4.h,
|
||||
eddp->nh.ip4.h.ihl);
|
||||
} else
|
||||
eddp->nh.ip6.h.payload_len = data_len + eddp->thl;
|
||||
/* prepare tcp hdr */
|
||||
if (data_len == (eddp->skb->len - eddp->skb_offset)){
|
||||
/* last segment -> set FIN and PSH flags */
|
||||
eddp->th.tcp.h.fin = tcph->fin;
|
||||
eddp->th.tcp.h.psh = tcph->psh;
|
||||
}
|
||||
if (eddp->skb->protocol == ETH_P_IP)
|
||||
hcsum = qeth_eddp_check_tcp4_hdr(eddp, data_len);
|
||||
else
|
||||
hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
|
||||
/* fill the next segment into the context */
|
||||
qeth_eddp_create_segment_hdrs(ctx, eddp);
|
||||
qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
|
||||
if (eddp->skb_offset >= eddp->skb->len)
|
||||
break;
|
||||
/* prepare headers for next round */
|
||||
if (eddp->skb->protocol == ETH_P_IP)
|
||||
eddp->nh.ip4.h.id++;
|
||||
eddp->th.tcp.h.seq += data_len;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
|
||||
struct sk_buff *skb, struct qeth_hdr *qhdr)
|
||||
{
|
||||
struct qeth_eddp_data *eddp = NULL;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpficx");
|
||||
/* create our segmentation headers and copy original headers */
|
||||
if (skb->protocol == ETH_P_IP)
|
||||
eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.iph,
|
||||
skb->nh.iph->ihl*4,
|
||||
(u8 *)skb->h.th, skb->h.th->doff*4);
|
||||
else
|
||||
eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.ipv6h,
|
||||
sizeof(struct ipv6hdr),
|
||||
(u8 *)skb->h.th, skb->h.th->doff*4);
|
||||
|
||||
if (eddp == NULL) {
|
||||
QETH_DBF_TEXT(trace, 2, "eddpfcnm");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
|
||||
memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN);
|
||||
#ifdef CONFIG_QETH_VLAN
|
||||
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
|
||||
eddp->vlan[0] = __constant_htons(skb->protocol);
|
||||
eddp->vlan[1] = htons(vlan_tx_tag_get(skb));
|
||||
}
|
||||
#endif /* CONFIG_QETH_VLAN */
|
||||
}
|
||||
/* the next flags will only be set on the last segment */
|
||||
eddp->th.tcp.h.fin = 0;
|
||||
eddp->th.tcp.h.psh = 0;
|
||||
eddp->skb = skb;
|
||||
/* begin segmentation and fill context */
|
||||
__qeth_eddp_fill_context_tcp(ctx, eddp);
|
||||
kfree(eddp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
|
||||
int hdr_len)
|
||||
{
|
||||
int skbs_per_page;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "eddpcanp");
|
||||
/* can we put multiple skbs in one page? */
|
||||
skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
|
||||
if (skbs_per_page > 1){
|
||||
ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
|
||||
skbs_per_page + 1;
|
||||
ctx->elements_per_skb = 1;
|
||||
} else {
|
||||
/* no -> how many elements per skb? */
|
||||
ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
|
||||
PAGE_SIZE) >> PAGE_SHIFT;
|
||||
ctx->num_pages = ctx->elements_per_skb *
|
||||
(skb_shinfo(skb)->tso_segs + 1);
|
||||
}
|
||||
ctx->num_elements = ctx->elements_per_skb *
|
||||
(skb_shinfo(skb)->tso_segs + 1);
|
||||
}
|
||||
|
||||
static inline struct qeth_eddp_context *
|
||||
qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
|
||||
int hdr_len)
|
||||
{
|
||||
struct qeth_eddp_context *ctx = NULL;
|
||||
u8 *addr;
|
||||
int i;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "creddpcg");
|
||||
/* create the context and allocate pages */
|
||||
ctx = kmalloc(sizeof(struct qeth_eddp_context), GFP_ATOMIC);
|
||||
if (ctx == NULL){
|
||||
QETH_DBF_TEXT(trace, 2, "ceddpcn1");
|
||||
return NULL;
|
||||
}
|
||||
memset(ctx, 0, sizeof(struct qeth_eddp_context));
|
||||
ctx->type = QETH_LARGE_SEND_EDDP;
|
||||
qeth_eddp_calc_num_pages(ctx, skb, hdr_len);
|
||||
if (ctx->elements_per_skb > QETH_MAX_BUFFER_ELEMENTS(card)){
|
||||
QETH_DBF_TEXT(trace, 2, "ceddpcis");
|
||||
kfree(ctx);
|
||||
return NULL;
|
||||
}
|
||||
ctx->pages = kmalloc(ctx->num_pages * sizeof(u8 *), GFP_ATOMIC);
|
||||
if (ctx->pages == NULL){
|
||||
QETH_DBF_TEXT(trace, 2, "ceddpcn2");
|
||||
kfree(ctx);
|
||||
return NULL;
|
||||
}
|
||||
memset(ctx->pages, 0, ctx->num_pages * sizeof(u8 *));
|
||||
for (i = 0; i < ctx->num_pages; ++i){
|
||||
addr = (u8 *)__get_free_page(GFP_ATOMIC);
|
||||
if (addr == NULL){
|
||||
QETH_DBF_TEXT(trace, 2, "ceddpcn3");
|
||||
ctx->num_pages = i;
|
||||
qeth_eddp_free_context(ctx);
|
||||
return NULL;
|
||||
}
|
||||
memset(addr, 0, PAGE_SIZE);
|
||||
ctx->pages[i] = addr;
|
||||
}
|
||||
ctx->elements = kmalloc(ctx->num_elements *
|
||||
sizeof(struct qeth_eddp_element), GFP_ATOMIC);
|
||||
if (ctx->elements == NULL){
|
||||
QETH_DBF_TEXT(trace, 2, "ceddpcn4");
|
||||
qeth_eddp_free_context(ctx);
|
||||
return NULL;
|
||||
}
|
||||
memset(ctx->elements, 0,
|
||||
ctx->num_elements * sizeof(struct qeth_eddp_element));
|
||||
/* reset num_elements; will be incremented again in fill_buffer to
|
||||
* reflect number of actually used elements */
|
||||
ctx->num_elements = 0;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static inline struct qeth_eddp_context *
|
||||
qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_hdr *qhdr)
|
||||
{
|
||||
struct qeth_eddp_context *ctx = NULL;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "creddpct");
|
||||
if (skb->protocol == ETH_P_IP)
|
||||
ctx = qeth_eddp_create_context_generic(card, skb,
|
||||
sizeof(struct qeth_hdr) + skb->nh.iph->ihl*4 +
|
||||
skb->h.th->doff*4);
|
||||
else if (skb->protocol == ETH_P_IPV6)
|
||||
ctx = qeth_eddp_create_context_generic(card, skb,
|
||||
sizeof(struct qeth_hdr) + sizeof(struct ipv6hdr) +
|
||||
skb->h.th->doff*4);
|
||||
else
|
||||
QETH_DBF_TEXT(trace, 2, "cetcpinv");
|
||||
|
||||
if (ctx == NULL) {
|
||||
QETH_DBF_TEXT(trace, 2, "creddpnl");
|
||||
return NULL;
|
||||
}
|
||||
if (qeth_eddp_fill_context_tcp(ctx, skb, qhdr)){
|
||||
QETH_DBF_TEXT(trace, 2, "ceddptfe");
|
||||
qeth_eddp_free_context(ctx);
|
||||
return NULL;
|
||||
}
|
||||
atomic_set(&ctx->refcnt, 1);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct qeth_eddp_context *
|
||||
qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_hdr *qhdr)
|
||||
{
|
||||
QETH_DBF_TEXT(trace, 5, "creddpc");
|
||||
switch (skb->sk->sk_protocol){
|
||||
case IPPROTO_TCP:
|
||||
return qeth_eddp_create_context_tcp(card, skb, qhdr);
|
||||
default:
|
||||
QETH_DBF_TEXT(trace, 2, "eddpinvp");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
85
drivers/s390/net/qeth_eddp.h
Normale Datei
85
drivers/s390/net/qeth_eddp.h
Normale Datei
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.5 $)
|
||||
*
|
||||
* Header file for qeth enhanced device driver pakcing.
|
||||
*
|
||||
* Copyright 2004 IBM Corporation
|
||||
*
|
||||
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
|
||||
*
|
||||
* $Revision: 1.5 $ $Date: 2005/03/24 09:04:18 $
|
||||
*
|
||||
*/
|
||||
#ifndef __QETH_EDDP_H__
|
||||
#define __QETH_EDDP_H__
|
||||
|
||||
struct qeth_eddp_element {
|
||||
u32 flags;
|
||||
u32 length;
|
||||
void *addr;
|
||||
};
|
||||
|
||||
struct qeth_eddp_context {
|
||||
atomic_t refcnt;
|
||||
enum qeth_large_send_types type;
|
||||
int num_pages; /* # of allocated pages */
|
||||
u8 **pages; /* pointers to pages */
|
||||
int offset; /* offset in ctx during creation */
|
||||
int num_elements; /* # of required 'SBALEs' */
|
||||
struct qeth_eddp_element *elements; /* array of 'SBALEs' */
|
||||
int elements_per_skb; /* # of 'SBALEs' per skb **/
|
||||
};
|
||||
|
||||
struct qeth_eddp_context_reference {
|
||||
struct list_head list;
|
||||
struct qeth_eddp_context *ctx;
|
||||
};
|
||||
|
||||
extern struct qeth_eddp_context *
|
||||
qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,struct qeth_hdr *);
|
||||
|
||||
extern void
|
||||
qeth_eddp_put_context(struct qeth_eddp_context *);
|
||||
|
||||
extern int
|
||||
qeth_eddp_fill_buffer(struct qeth_qdio_out_q *,struct qeth_eddp_context *,int);
|
||||
|
||||
extern void
|
||||
qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *);
|
||||
|
||||
extern int
|
||||
qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *,
|
||||
struct qeth_eddp_context *);
|
||||
/*
|
||||
* Data used for fragmenting a IP packet.
|
||||
*/
|
||||
struct qeth_eddp_data {
|
||||
struct qeth_hdr qh;
|
||||
struct ethhdr mac;
|
||||
u16 vlan[2];
|
||||
union {
|
||||
struct {
|
||||
struct iphdr h;
|
||||
u8 options[40];
|
||||
} ip4;
|
||||
struct {
|
||||
struct ipv6hdr h;
|
||||
} ip6;
|
||||
} nh;
|
||||
u8 nhl;
|
||||
void *nh_in_ctx; /* address of nh within the ctx */
|
||||
union {
|
||||
struct {
|
||||
struct tcphdr h;
|
||||
u8 options[40];
|
||||
} tcp;
|
||||
} th;
|
||||
u8 thl;
|
||||
void *th_in_ctx; /* address of th within the ctx */
|
||||
struct sk_buff *skb;
|
||||
int skb_offset;
|
||||
int frag;
|
||||
int frag_offset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* __QETH_EDDP_H__ */
|
163
drivers/s390/net/qeth_fs.h
Normale Datei
163
drivers/s390/net/qeth_fs.h
Normale Datei
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* linux/drivers/s390/net/qeth_fs.h
|
||||
*
|
||||
* Linux on zSeries OSA Express and HiperSockets support.
|
||||
*
|
||||
* This header file contains definitions related to sysfs and procfs.
|
||||
*
|
||||
* Copyright 2000,2003 IBM Corporation
|
||||
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
|
||||
*
|
||||
*/
|
||||
#ifndef __QETH_FS_H__
|
||||
#define __QETH_FS_H__
|
||||
|
||||
#define VERSION_QETH_FS_H "$Revision: 1.9 $"
|
||||
|
||||
extern const char *VERSION_QETH_PROC_C;
|
||||
extern const char *VERSION_QETH_SYS_C;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern int
|
||||
qeth_create_procfs_entries(void);
|
||||
|
||||
extern void
|
||||
qeth_remove_procfs_entries(void);
|
||||
#else
|
||||
static inline int
|
||||
qeth_create_procfs_entries(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qeth_remove_procfs_entries(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
extern int
|
||||
qeth_create_device_attributes(struct device *dev);
|
||||
|
||||
extern void
|
||||
qeth_remove_device_attributes(struct device *dev);
|
||||
|
||||
extern int
|
||||
qeth_create_driver_attributes(void);
|
||||
|
||||
extern void
|
||||
qeth_remove_driver_attributes(void);
|
||||
|
||||
/*
|
||||
* utility functions used in qeth_proc.c and qeth_sys.c
|
||||
*/
|
||||
|
||||
static inline const char *
|
||||
qeth_get_checksum_str(struct qeth_card *card)
|
||||
{
|
||||
if (card->options.checksum_type == SW_CHECKSUMMING)
|
||||
return "sw";
|
||||
else if (card->options.checksum_type == HW_CHECKSUMMING)
|
||||
return "hw";
|
||||
else
|
||||
return "no";
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
qeth_get_prioq_str(struct qeth_card *card, char *buf)
|
||||
{
|
||||
if (card->qdio.do_prio_queueing == QETH_NO_PRIO_QUEUEING)
|
||||
sprintf(buf, "always_q_%i", card->qdio.default_out_queue);
|
||||
else
|
||||
strcpy(buf, (card->qdio.do_prio_queueing ==
|
||||
QETH_PRIO_Q_ING_PREC)?
|
||||
"by_prec." : "by_ToS");
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
qeth_get_bufsize_str(struct qeth_card *card)
|
||||
{
|
||||
if (card->qdio.in_buf_size == 16384)
|
||||
return "16k";
|
||||
else if (card->qdio.in_buf_size == 24576)
|
||||
return "24k";
|
||||
else if (card->qdio.in_buf_size == 32768)
|
||||
return "32k";
|
||||
else if (card->qdio.in_buf_size == 40960)
|
||||
return "40k";
|
||||
else
|
||||
return "64k";
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
qeth_get_cardname(struct qeth_card *card)
|
||||
{
|
||||
if (card->info.guestlan) {
|
||||
switch (card->info.type) {
|
||||
case QETH_CARD_TYPE_OSAE:
|
||||
return " Guest LAN QDIO";
|
||||
case QETH_CARD_TYPE_IQD:
|
||||
return " Guest LAN Hiper";
|
||||
default:
|
||||
return " unknown";
|
||||
}
|
||||
} else {
|
||||
switch (card->info.type) {
|
||||
case QETH_CARD_TYPE_OSAE:
|
||||
return " OSD Express";
|
||||
case QETH_CARD_TYPE_IQD:
|
||||
return " HiperSockets";
|
||||
default:
|
||||
return " unknown";
|
||||
}
|
||||
}
|
||||
return " n/a";
|
||||
}
|
||||
|
||||
/* max length to be returned: 14 */
|
||||
static inline const char *
|
||||
qeth_get_cardname_short(struct qeth_card *card)
|
||||
{
|
||||
if (card->info.guestlan){
|
||||
switch (card->info.type){
|
||||
case QETH_CARD_TYPE_OSAE:
|
||||
return "GuestLAN QDIO";
|
||||
case QETH_CARD_TYPE_IQD:
|
||||
return "GuestLAN Hiper";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
} else {
|
||||
switch (card->info.type) {
|
||||
case QETH_CARD_TYPE_OSAE:
|
||||
switch (card->info.link_type) {
|
||||
case QETH_LINK_TYPE_FAST_ETH:
|
||||
return "OSD_100";
|
||||
case QETH_LINK_TYPE_HSTR:
|
||||
return "HSTR";
|
||||
case QETH_LINK_TYPE_GBIT_ETH:
|
||||
return "OSD_1000";
|
||||
case QETH_LINK_TYPE_10GBIT_ETH:
|
||||
return "OSD_10GIG";
|
||||
case QETH_LINK_TYPE_LANE_ETH100:
|
||||
return "OSD_FE_LANE";
|
||||
case QETH_LINK_TYPE_LANE_TR:
|
||||
return "OSD_TR_LANE";
|
||||
case QETH_LINK_TYPE_LANE_ETH1000:
|
||||
return "OSD_GbE_LANE";
|
||||
case QETH_LINK_TYPE_LANE:
|
||||
return "OSD_ATM_LANE";
|
||||
default:
|
||||
return "OSD_Express";
|
||||
}
|
||||
case QETH_CARD_TYPE_IQD:
|
||||
return "HiperSockets";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
#endif /* __QETH_FS_H__ */
|
8236
drivers/s390/net/qeth_main.c
Normale Datei
8236
drivers/s390/net/qeth_main.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
168
drivers/s390/net/qeth_mpc.c
Normale Datei
168
drivers/s390/net/qeth_mpc.c
Normale Datei
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* linux/drivers/s390/net/qeth_mpc.c
|
||||
*
|
||||
* Linux on zSeries OSA Express and HiperSockets support
|
||||
*
|
||||
* Copyright 2000,2003 IBM Corporation
|
||||
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
|
||||
* Thomas Spatzier <tspat@de.ibm.com>
|
||||
*
|
||||
*/
|
||||
#include <asm/cio.h>
|
||||
#include "qeth_mpc.h"
|
||||
|
||||
const char *VERSION_QETH_MPC_C = "$Revision: 1.11 $";
|
||||
|
||||
unsigned char IDX_ACTIVATE_READ[]={
|
||||
0x00,0x00,0x80,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x19,0x01,0x01,0x80, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0xc8,0xc1,
|
||||
0xd3,0xd3,0xd6,0xd3, 0xc5,0x40,0x00,0x00,
|
||||
0x00,0x00
|
||||
};
|
||||
|
||||
unsigned char IDX_ACTIVATE_WRITE[]={
|
||||
0x00,0x00,0x80,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x15,0x01,0x01,0x80, 0x00,0x00,0x00,0x00,
|
||||
0xff,0xff,0x00,0x00, 0x00,0x00,0xc8,0xc1,
|
||||
0xd3,0xd3,0xd6,0xd3, 0xc5,0x40,0x00,0x00,
|
||||
0x00,0x00
|
||||
};
|
||||
|
||||
unsigned char CM_ENABLE[]={
|
||||
0x00,0xe0,0x00,0x00, 0x00,0x00,0x00,0x01,
|
||||
0x00,0x00,0x00,0x14, 0x00,0x00,0x00,0x63,
|
||||
0x10,0x00,0x00,0x01,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x81,0x7e,0x00,0x01, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x24,0x00,0x23,
|
||||
0x00,0x00,0x23,0x05, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x01,0x00,0x00,0x23, 0x00,0x00,0x00,0x40,
|
||||
0x00,0x0c,0x41,0x02, 0x00,0x17,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x0b,0x04,0x01,
|
||||
0x7e,0x04,0x05,0x00, 0x01,0x01,0x0f,
|
||||
0x00,
|
||||
0x0c,0x04,0x02,0xff, 0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff
|
||||
};
|
||||
|
||||
unsigned char CM_SETUP[]={
|
||||
0x00,0xe0,0x00,0x00, 0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x00,0x14, 0x00,0x00,0x00,0x64,
|
||||
0x10,0x00,0x00,0x01,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x81,0x7e,0x00,0x01, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x24,0x00,0x24,
|
||||
0x00,0x00,0x24,0x05, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x01,0x00,0x00,0x24, 0x00,0x00,0x00,0x40,
|
||||
0x00,0x0c,0x41,0x04, 0x00,0x18,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x09,0x04,0x04,
|
||||
0x05,0x00,0x01,0x01, 0x11,
|
||||
0x00,0x09,0x04,
|
||||
0x05,0x05,0x00,0x00, 0x00,0x00,
|
||||
0x00,0x06,
|
||||
0x04,0x06,0xc8,0x00
|
||||
};
|
||||
|
||||
unsigned char ULP_ENABLE[]={
|
||||
0x00,0xe0,0x00,0x00, 0x00,0x00,0x00,0x03,
|
||||
0x00,0x00,0x00,0x14, 0x00,0x00,0x00,0x6b,
|
||||
0x10,0x00,0x00,0x01,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x41,0x7e,0x00,0x01, 0x00,0x00,0x00,0x01,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x24,0x00,0x2b,
|
||||
0x00,0x00,0x2b,0x05, 0x20,0x01,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x01,0x00,0x00,0x2b, 0x00,0x00,0x00,0x40,
|
||||
0x00,0x0c,0x41,0x02, 0x00,0x1f,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x0b,0x04,0x01,
|
||||
0x03,0x04,0x05,0x00, 0x01,0x01,0x12,
|
||||
0x00,
|
||||
0x14,0x04,0x0a,0x00, 0x20,0x00,0x00,0xff,
|
||||
0xff,0x00,0x08,0xc8, 0xe8,0xc4,0xf1,0xc7,
|
||||
0xf1,0x00,0x00
|
||||
};
|
||||
|
||||
unsigned char ULP_SETUP[]={
|
||||
0x00,0xe0,0x00,0x00, 0x00,0x00,0x00,0x04,
|
||||
0x00,0x00,0x00,0x14, 0x00,0x00,0x00,0x6c,
|
||||
0x10,0x00,0x00,0x01,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x41,0x7e,0x00,0x01, 0x00,0x00,0x00,0x02,
|
||||
0x00,0x00,0x00,0x01, 0x00,0x24,0x00,0x2c,
|
||||
0x00,0x00,0x2c,0x05, 0x20,0x01,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x01,0x00,0x00,0x2c, 0x00,0x00,0x00,0x40,
|
||||
0x00,0x0c,0x41,0x04, 0x00,0x20,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x09,0x04,0x04,
|
||||
0x05,0x00,0x01,0x01, 0x14,
|
||||
0x00,0x09,0x04,
|
||||
0x05,0x05,0x30,0x01, 0x00,0x00,
|
||||
0x00,0x06,
|
||||
0x04,0x06,0x40,0x00,
|
||||
0x00,0x08,0x04,0x0b,
|
||||
0x00,0x00,0x00,0x00
|
||||
};
|
||||
|
||||
unsigned char DM_ACT[]={
|
||||
0x00,0xe0,0x00,0x00, 0x00,0x00,0x00,0x05,
|
||||
0x00,0x00,0x00,0x14, 0x00,0x00,0x00,0x55,
|
||||
0x10,0x00,0x00,0x01,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x41,0x7e,0x00,0x01, 0x00,0x00,0x00,0x03,
|
||||
0x00,0x00,0x00,0x02, 0x00,0x24,0x00,0x15,
|
||||
0x00,0x00,0x2c,0x05, 0x20,0x01,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x01,0x00,0x00,0x15, 0x00,0x00,0x00,0x40,
|
||||
0x00,0x0c,0x43,0x60, 0x00,0x09,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x09,0x04,0x04,
|
||||
0x05,0x40,0x01,0x01, 0x00
|
||||
};
|
||||
|
||||
unsigned char IPA_PDU_HEADER[]={
|
||||
0x00,0xe0,0x00,0x00, 0x77,0x77,0x77,0x77,
|
||||
0x00,0x00,0x00,0x14, 0x00,0x00,
|
||||
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))/256,
|
||||
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))%256,
|
||||
0x10,0x00,0x00,0x01, 0x00,0x00,0x00,0x00,
|
||||
0xc1,0x03,0x00,0x01, 0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x24,
|
||||
sizeof(struct qeth_ipa_cmd)/256,
|
||||
sizeof(struct qeth_ipa_cmd)%256,
|
||||
0x00,
|
||||
sizeof(struct qeth_ipa_cmd)/256,
|
||||
sizeof(struct qeth_ipa_cmd),0x05, 0x77,0x77,0x77,0x77,
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
||||
0x01,0x00,
|
||||
sizeof(struct qeth_ipa_cmd)/256,
|
||||
sizeof(struct qeth_ipa_cmd)%256,
|
||||
0x00,0x00,0x00,0x40,
|
||||
};
|
||||
|
||||
unsigned char WRITE_CCW[]={
|
||||
0x01,CCW_FLAG_SLI,0,0,
|
||||
0,0,0,0
|
||||
};
|
||||
|
||||
unsigned char READ_CCW[]={
|
||||
0x02,CCW_FLAG_SLI,0,0,
|
||||
0,0,0,0
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
538
drivers/s390/net/qeth_mpc.h
Normale Datei
538
drivers/s390/net/qeth_mpc.h
Normale Datei
@@ -0,0 +1,538 @@
|
||||
/*
|
||||
* linux/drivers/s390/net/qeth_mpc.h
|
||||
*
|
||||
* Linux on zSeries OSA Express and HiperSockets support
|
||||
*
|
||||
* Copyright 2000,2003 IBM Corporation
|
||||
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
|
||||
* Thomas Spatzier <tspat@de.ibm.com>
|
||||
* Frank Pavlic <pavlic@de.ibm.com>
|
||||
*
|
||||
*/
|
||||
#ifndef __QETH_MPC_H__
|
||||
#define __QETH_MPC_H__
|
||||
|
||||
#include <asm/qeth.h>
|
||||
|
||||
#define VERSION_QETH_MPC_H "$Revision: 1.43 $"
|
||||
|
||||
extern const char *VERSION_QETH_MPC_C;
|
||||
|
||||
#define IPA_PDU_HEADER_SIZE 0x40
|
||||
#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer+0x0e)
|
||||
#define QETH_IPA_PDU_LEN_PDU1(buffer) (buffer+0x26)
|
||||
#define QETH_IPA_PDU_LEN_PDU2(buffer) (buffer+0x2a)
|
||||
#define QETH_IPA_PDU_LEN_PDU3(buffer) (buffer+0x3a)
|
||||
|
||||
extern unsigned char IPA_PDU_HEADER[];
|
||||
#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer+0x2c)
|
||||
|
||||
#define IPA_CMD_LENGTH (IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd))
|
||||
|
||||
#define QETH_SEQ_NO_LENGTH 4
|
||||
#define QETH_MPC_TOKEN_LENGTH 4
|
||||
#define QETH_MCL_LENGTH 4
|
||||
#define OSA_ADDR_LEN 6
|
||||
|
||||
#define QETH_TIMEOUT (10 * HZ)
|
||||
#define QETH_IPA_TIMEOUT (45 * HZ)
|
||||
#define QETH_IDX_COMMAND_SEQNO 0xffff0000
|
||||
#define SR_INFO_LEN 16
|
||||
|
||||
#define QETH_CLEAR_CHANNEL_PARM -10
|
||||
#define QETH_HALT_CHANNEL_PARM -11
|
||||
|
||||
/*****************************************************************************/
|
||||
/* IP Assist related definitions */
|
||||
/*****************************************************************************/
|
||||
#define IPA_CMD_INITIATOR_HOST 0x00
|
||||
#define IPA_CMD_INITIATOR_HYDRA 0x01
|
||||
#define IPA_CMD_PRIM_VERSION_NO 0x01
|
||||
|
||||
enum qeth_card_types {
|
||||
QETH_CARD_TYPE_UNKNOWN = 0,
|
||||
QETH_CARD_TYPE_OSAE = 10,
|
||||
QETH_CARD_TYPE_IQD = 1234,
|
||||
};
|
||||
|
||||
#define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18
|
||||
/* only the first two bytes are looked at in qeth_get_cardname_short */
|
||||
enum qeth_link_types {
|
||||
QETH_LINK_TYPE_FAST_ETH = 0x01,
|
||||
QETH_LINK_TYPE_HSTR = 0x02,
|
||||
QETH_LINK_TYPE_GBIT_ETH = 0x03,
|
||||
QETH_LINK_TYPE_10GBIT_ETH = 0x10,
|
||||
QETH_LINK_TYPE_LANE_ETH100 = 0x81,
|
||||
QETH_LINK_TYPE_LANE_TR = 0x82,
|
||||
QETH_LINK_TYPE_LANE_ETH1000 = 0x83,
|
||||
QETH_LINK_TYPE_LANE = 0x88,
|
||||
QETH_LINK_TYPE_ATM_NATIVE = 0x90,
|
||||
};
|
||||
|
||||
enum qeth_tr_macaddr_modes {
|
||||
QETH_TR_MACADDR_NONCANONICAL = 0,
|
||||
QETH_TR_MACADDR_CANONICAL = 1,
|
||||
};
|
||||
|
||||
enum qeth_tr_broadcast_modes {
|
||||
QETH_TR_BROADCAST_ALLRINGS = 0,
|
||||
QETH_TR_BROADCAST_LOCAL = 1,
|
||||
};
|
||||
|
||||
/* these values match CHECKSUM_* in include/linux/skbuff.h */
|
||||
enum qeth_checksum_types {
|
||||
SW_CHECKSUMMING = 0, /* TODO: set to bit flag used in IPA Command */
|
||||
HW_CHECKSUMMING = 1,
|
||||
NO_CHECKSUMMING = 2,
|
||||
};
|
||||
#define QETH_CHECKSUM_DEFAULT SW_CHECKSUMMING
|
||||
|
||||
/*
|
||||
* Routing stuff
|
||||
*/
|
||||
#define RESET_ROUTING_FLAG 0x10 /* indicate that routing type shall be set */
|
||||
enum qeth_routing_types {
|
||||
NO_ROUTER = 0, /* TODO: set to bit flag used in IPA Command */
|
||||
PRIMARY_ROUTER = 1,
|
||||
SECONDARY_ROUTER = 2,
|
||||
MULTICAST_ROUTER = 3,
|
||||
PRIMARY_CONNECTOR = 4,
|
||||
SECONDARY_CONNECTOR = 5,
|
||||
};
|
||||
|
||||
|
||||
/* IPA Commands */
|
||||
enum qeth_ipa_cmds {
|
||||
IPA_CMD_STARTLAN = 0x01,
|
||||
IPA_CMD_STOPLAN = 0x02,
|
||||
IPA_CMD_SETVMAC = 0x21,
|
||||
IPA_CMD_DELVMAC = 0x22,
|
||||
IPA_CMD_SETGMAC = 0x23,
|
||||
IPA_CMD_DELGMAC = 0x24,
|
||||
IPA_CMD_SETVLAN = 0x25,
|
||||
IPA_CMD_DELVLAN = 0x26,
|
||||
IPA_CMD_SETIP = 0xb1,
|
||||
IPA_CMD_DELIP = 0xb7,
|
||||
IPA_CMD_QIPASSIST = 0xb2,
|
||||
IPA_CMD_SETASSPARMS = 0xb3,
|
||||
IPA_CMD_SETIPM = 0xb4,
|
||||
IPA_CMD_DELIPM = 0xb5,
|
||||
IPA_CMD_SETRTG = 0xb6,
|
||||
IPA_CMD_SETADAPTERPARMS = 0xb8,
|
||||
IPA_CMD_IPFRAME = 0xb9,
|
||||
IPA_CMD_ADD_ADDR_ENTRY = 0xc1,
|
||||
IPA_CMD_DELETE_ADDR_ENTRY = 0xc2,
|
||||
IPA_CMD_CREATE_ADDR = 0xc3,
|
||||
IPA_CMD_DESTROY_ADDR = 0xc4,
|
||||
IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1,
|
||||
IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2,
|
||||
};
|
||||
|
||||
enum qeth_ip_ass_cmds {
|
||||
IPA_CMD_ASS_START = 0x0001,
|
||||
IPA_CMD_ASS_STOP = 0x0002,
|
||||
IPA_CMD_ASS_CONFIGURE = 0x0003,
|
||||
IPA_CMD_ASS_ENABLE = 0x0004,
|
||||
};
|
||||
|
||||
enum qeth_arp_process_subcmds {
|
||||
IPA_CMD_ASS_ARP_SET_NO_ENTRIES = 0x0003,
|
||||
IPA_CMD_ASS_ARP_QUERY_CACHE = 0x0004,
|
||||
IPA_CMD_ASS_ARP_ADD_ENTRY = 0x0005,
|
||||
IPA_CMD_ASS_ARP_REMOVE_ENTRY = 0x0006,
|
||||
IPA_CMD_ASS_ARP_FLUSH_CACHE = 0x0007,
|
||||
IPA_CMD_ASS_ARP_QUERY_INFO = 0x0104,
|
||||
IPA_CMD_ASS_ARP_QUERY_STATS = 0x0204,
|
||||
};
|
||||
|
||||
/* Return Codes for IPA Commands */
|
||||
enum qeth_ipa_return_codes {
|
||||
IPA_RC_SUCCESS = 0x0000,
|
||||
IPA_RC_NOTSUPP = 0x0001,
|
||||
IPA_RC_NO_ACCESS = 0x0002,
|
||||
IPA_RC_FAILED = 0x0003,
|
||||
IPA_RC_DATA_MISMATCH = 0xe001,
|
||||
IPA_RC_INVALID_LAN_TYPE = 0xe003,
|
||||
IPA_RC_INVALID_LAN_NO = 0xe004,
|
||||
IPA_RC_IPADDR_ALREADY_REG = 0xe005,
|
||||
IPA_RC_IPADDR_TABLE_FULL = 0xe006,
|
||||
IPA_RC_IPADDR_ALREADY_USED = 0xe00a,
|
||||
IPA_RC_ASSNO_NOT_SUPP = 0xe00d,
|
||||
IPA_RC_ASSCMD_START_FAILED = 0xe00e,
|
||||
IPA_RC_ASSCMD_PART_SUCCESS = 0xe00f,
|
||||
IPA_RC_IPADDR_NOT_DEFINED = 0xe010,
|
||||
IPA_RC_LAN_OFFLINE = 0xe080,
|
||||
};
|
||||
|
||||
/* IPA function flags; each flag marks availability of respective function */
|
||||
enum qeth_ipa_funcs {
|
||||
IPA_ARP_PROCESSING = 0x00000001L,
|
||||
IPA_INBOUND_CHECKSUM = 0x00000002L,
|
||||
IPA_OUTBOUND_CHECKSUM = 0x00000004L,
|
||||
IPA_IP_FRAGMENTATION = 0x00000008L,
|
||||
IPA_FILTERING = 0x00000010L,
|
||||
IPA_IPV6 = 0x00000020L,
|
||||
IPA_MULTICASTING = 0x00000040L,
|
||||
IPA_IP_REASSEMBLY = 0x00000080L,
|
||||
IPA_QUERY_ARP_COUNTERS = 0x00000100L,
|
||||
IPA_QUERY_ARP_ADDR_INFO = 0x00000200L,
|
||||
IPA_SETADAPTERPARMS = 0x00000400L,
|
||||
IPA_VLAN_PRIO = 0x00000800L,
|
||||
IPA_PASSTHRU = 0x00001000L,
|
||||
IPA_FULL_VLAN = 0x00004000L,
|
||||
IPA_SOURCE_MAC = 0x00010000L,
|
||||
IPA_OSA_MC_ROUTER = 0x00020000L,
|
||||
IPA_QUERY_ARP_ASSIST = 0x00040000L,
|
||||
IPA_INBOUND_TSO = 0x00080000L,
|
||||
IPA_OUTBOUND_TSO = 0x00100000L,
|
||||
};
|
||||
|
||||
/* SETIP/DELIP IPA Command: ***************************************************/
|
||||
enum qeth_ipa_setdelip_flags {
|
||||
QETH_IPA_SETDELIP_DEFAULT = 0x00L, /* default */
|
||||
QETH_IPA_SETIP_VIPA_FLAG = 0x01L, /* no grat. ARP */
|
||||
QETH_IPA_SETIP_TAKEOVER_FLAG = 0x02L, /* nofail on grat. ARP */
|
||||
QETH_IPA_DELIP_ADDR_2_B_TAKEN_OVER = 0x20L,
|
||||
QETH_IPA_DELIP_VIPA_FLAG = 0x40L,
|
||||
QETH_IPA_DELIP_ADDR_NEEDS_SETIP = 0x80L,
|
||||
};
|
||||
|
||||
/* SETADAPTER IPA Command: ****************************************************/
|
||||
enum qeth_ipa_setadp_cmd {
|
||||
IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x01,
|
||||
IPA_SETADP_ALTER_MAC_ADDRESS = 0x02,
|
||||
IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x04,
|
||||
IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x08,
|
||||
IPA_SETADP_SET_ADDRESSING_MODE = 0x10,
|
||||
IPA_SETADP_SET_CONFIG_PARMS = 0x20,
|
||||
IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x40,
|
||||
IPA_SETADP_SET_BROADCAST_MODE = 0x80,
|
||||
IPA_SETADP_SEND_OSA_MESSAGE = 0x0100,
|
||||
IPA_SETADP_SET_SNMP_CONTROL = 0x0200,
|
||||
IPA_SETADP_READ_SNMP_PARMS = 0x0400,
|
||||
IPA_SETADP_WRITE_SNMP_PARMS = 0x0800,
|
||||
IPA_SETADP_QUERY_CARD_INFO = 0x1000,
|
||||
};
|
||||
enum qeth_ipa_mac_ops {
|
||||
CHANGE_ADDR_READ_MAC = 0,
|
||||
CHANGE_ADDR_REPLACE_MAC = 1,
|
||||
CHANGE_ADDR_ADD_MAC = 2,
|
||||
CHANGE_ADDR_DEL_MAC = 4,
|
||||
CHANGE_ADDR_RESET_MAC = 8,
|
||||
};
|
||||
enum qeth_ipa_addr_ops {
|
||||
CHANGE_ADDR_READ_ADDR = 0,
|
||||
CHANGE_ADDR_ADD_ADDR = 1,
|
||||
CHANGE_ADDR_DEL_ADDR = 2,
|
||||
CHANGE_ADDR_FLUSH_ADDR_TABLE = 4,
|
||||
|
||||
|
||||
};
|
||||
/* (SET)DELIP(M) IPA stuff ***************************************************/
|
||||
struct qeth_ipacmd_setdelip4 {
|
||||
__u8 ip_addr[4];
|
||||
__u8 mask[4];
|
||||
__u32 flags;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_ipacmd_setdelip6 {
|
||||
__u8 ip_addr[16];
|
||||
__u8 mask[16];
|
||||
__u32 flags;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_ipacmd_setdelipm {
|
||||
__u8 mac[6];
|
||||
__u8 padding[2];
|
||||
__u8 ip6[12];
|
||||
__u8 ip4[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_ipacmd_layer2setdelmac {
|
||||
__u32 mac_length;
|
||||
__u8 mac[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_ipacmd_layer2setdelvlan {
|
||||
__u16 vlan_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct qeth_ipacmd_setassparms_hdr {
|
||||
__u32 assist_no;
|
||||
__u16 length;
|
||||
__u16 command_code;
|
||||
__u16 return_code;
|
||||
__u8 number_of_replies;
|
||||
__u8 seq_no;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct qeth_arp_query_data {
|
||||
__u16 request_bits;
|
||||
__u16 reply_bits;
|
||||
__u32 no_entries;
|
||||
char data;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* used as parameter for arp_query reply */
|
||||
struct qeth_arp_query_info {
|
||||
__u32 udata_len;
|
||||
__u16 mask_bits;
|
||||
__u32 udata_offset;
|
||||
__u32 no_entries;
|
||||
char *udata;
|
||||
};
|
||||
|
||||
/* SETASSPARMS IPA Command: */
|
||||
struct qeth_ipacmd_setassparms {
|
||||
struct qeth_ipacmd_setassparms_hdr hdr;
|
||||
union {
|
||||
__u32 flags_32bit;
|
||||
struct qeth_arp_cache_entry add_arp_entry;
|
||||
struct qeth_arp_query_data query_arp;
|
||||
__u8 ip[16];
|
||||
} data;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* SETRTG IPA Command: ****************************************************/
|
||||
struct qeth_set_routing {
|
||||
__u8 type;
|
||||
};
|
||||
|
||||
/* SETADAPTERPARMS IPA Command: *******************************************/
|
||||
struct qeth_query_cmds_supp {
|
||||
__u32 no_lantypes_supp;
|
||||
__u8 lan_type;
|
||||
__u8 reserved1[3];
|
||||
__u32 supported_cmds;
|
||||
__u8 reserved2[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_change_addr {
|
||||
__u32 cmd;
|
||||
__u32 addr_size;
|
||||
__u32 no_macs;
|
||||
__u8 addr[OSA_ADDR_LEN];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
struct qeth_snmp_cmd {
|
||||
__u8 token[16];
|
||||
__u32 request;
|
||||
__u32 interface;
|
||||
__u32 returncode;
|
||||
__u32 firmwarelevel;
|
||||
__u32 seqno;
|
||||
__u8 data;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_snmp_ureq_hdr {
|
||||
__u32 data_len;
|
||||
__u32 req_len;
|
||||
__u32 reserved1;
|
||||
__u32 reserved2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_snmp_ureq {
|
||||
struct qeth_snmp_ureq_hdr hdr;
|
||||
struct qeth_snmp_cmd cmd;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct qeth_ipacmd_setadpparms_hdr {
|
||||
__u32 supp_hw_cmds;
|
||||
__u32 reserved1;
|
||||
__u16 cmdlength;
|
||||
__u16 reserved2;
|
||||
__u32 command_code;
|
||||
__u16 return_code;
|
||||
__u8 used_total;
|
||||
__u8 seq_no;
|
||||
__u32 reserved3;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_ipacmd_setadpparms {
|
||||
struct qeth_ipacmd_setadpparms_hdr hdr;
|
||||
union {
|
||||
struct qeth_query_cmds_supp query_cmds_supp;
|
||||
struct qeth_change_addr change_addr;
|
||||
struct qeth_snmp_cmd snmp;
|
||||
__u32 mode;
|
||||
} data;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* IPFRAME IPA Command: ***************************************************/
|
||||
/* TODO: define in analogy to commands define above */
|
||||
|
||||
/* ADD_ADDR_ENTRY IPA Command: ********************************************/
|
||||
/* TODO: define in analogy to commands define above */
|
||||
|
||||
/* DELETE_ADDR_ENTRY IPA Command: *****************************************/
|
||||
/* TODO: define in analogy to commands define above */
|
||||
|
||||
/* CREATE_ADDR IPA Command: ***********************************************/
|
||||
struct qeth_create_destroy_address {
|
||||
__u8 unique_id[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* REGISTER_LOCAL_ADDR IPA Command: ***************************************/
|
||||
/* TODO: define in analogy to commands define above */
|
||||
|
||||
/* UNREGISTER_LOCAL_ADDR IPA Command: *************************************/
|
||||
/* TODO: define in analogy to commands define above */
|
||||
|
||||
/* Header for each IPA command */
|
||||
struct qeth_ipacmd_hdr {
|
||||
__u8 command;
|
||||
__u8 initiator;
|
||||
__u16 seqno;
|
||||
__u16 return_code;
|
||||
__u8 adapter_type;
|
||||
__u8 rel_adapter_no;
|
||||
__u8 prim_version_no;
|
||||
__u8 param_count;
|
||||
__u16 prot_version;
|
||||
__u32 ipa_supported;
|
||||
__u32 ipa_enabled;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* The IPA command itself */
|
||||
struct qeth_ipa_cmd {
|
||||
struct qeth_ipacmd_hdr hdr;
|
||||
union {
|
||||
struct qeth_ipacmd_setdelip4 setdelip4;
|
||||
struct qeth_ipacmd_setdelip6 setdelip6;
|
||||
struct qeth_ipacmd_setdelipm setdelipm;
|
||||
struct qeth_ipacmd_setassparms setassparms;
|
||||
struct qeth_ipacmd_layer2setdelmac setdelmac;
|
||||
struct qeth_ipacmd_layer2setdelvlan setdelvlan;
|
||||
struct qeth_create_destroy_address create_destroy_addr;
|
||||
struct qeth_ipacmd_setadpparms setadapterparms;
|
||||
struct qeth_set_routing setrtg;
|
||||
} data;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* special command for ARP processing.
|
||||
* this is not included in setassparms command before, because we get
|
||||
* problem with the size of struct qeth_ipacmd_setassparms otherwise
|
||||
*/
|
||||
enum qeth_ipa_arp_return_codes {
|
||||
QETH_IPA_ARP_RC_SUCCESS = 0x0000,
|
||||
QETH_IPA_ARP_RC_FAILED = 0x0001,
|
||||
QETH_IPA_ARP_RC_NOTSUPP = 0x0002,
|
||||
QETH_IPA_ARP_RC_OUT_OF_RANGE = 0x0003,
|
||||
QETH_IPA_ARP_RC_Q_NOTSUPP = 0x0004,
|
||||
QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008,
|
||||
};
|
||||
|
||||
#define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
|
||||
sizeof(struct qeth_ipacmd_setassparms_hdr))
|
||||
#define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \
|
||||
QETH_SETASS_BASE_LEN)
|
||||
#define QETH_SETADP_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
|
||||
sizeof(struct qeth_ipacmd_setadpparms_hdr))
|
||||
#define QETH_SNMP_SETADP_CMDLENGTH 16
|
||||
|
||||
#define QETH_ARP_DATA_SIZE 3968
|
||||
#define QETH_ARP_CMD_LEN (QETH_ARP_DATA_SIZE + 8)
|
||||
/* Helper functions */
|
||||
#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* END OF IP Assist related definitions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
extern unsigned char WRITE_CCW[];
|
||||
extern unsigned char READ_CCW[];
|
||||
|
||||
extern unsigned char CM_ENABLE[];
|
||||
#define CM_ENABLE_SIZE 0x63
|
||||
#define QETH_CM_ENABLE_ISSUER_RM_TOKEN(buffer) (buffer+0x2c)
|
||||
#define QETH_CM_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
|
||||
#define QETH_CM_ENABLE_USER_DATA(buffer) (buffer+0x5b)
|
||||
|
||||
#define QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer) \
|
||||
(PDU_ENCAPSULATION(buffer)+ 0x13)
|
||||
|
||||
|
||||
extern unsigned char CM_SETUP[];
|
||||
#define CM_SETUP_SIZE 0x64
|
||||
#define QETH_CM_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
|
||||
#define QETH_CM_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
|
||||
#define QETH_CM_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
|
||||
|
||||
#define QETH_CM_SETUP_RESP_DEST_ADDR(buffer) \
|
||||
(PDU_ENCAPSULATION(buffer) + 0x1a)
|
||||
|
||||
extern unsigned char ULP_ENABLE[];
|
||||
#define ULP_ENABLE_SIZE 0x6b
|
||||
#define QETH_ULP_ENABLE_LINKNUM(buffer) (buffer+0x61)
|
||||
#define QETH_ULP_ENABLE_DEST_ADDR(buffer) (buffer+0x2c)
|
||||
#define QETH_ULP_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
|
||||
#define QETH_ULP_ENABLE_PORTNAME_AND_LL(buffer) (buffer+0x62)
|
||||
#define QETH_ULP_ENABLE_RESP_FILTER_TOKEN(buffer) \
|
||||
(PDU_ENCAPSULATION(buffer) + 0x13)
|
||||
#define QETH_ULP_ENABLE_RESP_MAX_MTU(buffer) \
|
||||
(PDU_ENCAPSULATION(buffer)+ 0x1f)
|
||||
#define QETH_ULP_ENABLE_RESP_DIFINFO_LEN(buffer) \
|
||||
(PDU_ENCAPSULATION(buffer) + 0x17)
|
||||
#define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) \
|
||||
(PDU_ENCAPSULATION(buffer)+ 0x2b)
|
||||
/* Layer 2 defintions */
|
||||
#define QETH_PROT_LAYER2 0x08
|
||||
#define QETH_PROT_TCPIP 0x03
|
||||
#define QETH_ULP_ENABLE_PROT_TYPE(buffer) (buffer+0x50)
|
||||
#define QETH_IPA_CMD_PROT_TYPE(buffer) (buffer+0x19)
|
||||
|
||||
extern unsigned char ULP_SETUP[];
|
||||
#define ULP_SETUP_SIZE 0x6c
|
||||
#define QETH_ULP_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
|
||||
#define QETH_ULP_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
|
||||
#define QETH_ULP_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
|
||||
#define QETH_ULP_SETUP_CUA(buffer) (buffer+0x68)
|
||||
#define QETH_ULP_SETUP_REAL_DEVADDR(buffer) (buffer+0x6a)
|
||||
|
||||
#define QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(buffer) \
|
||||
(PDU_ENCAPSULATION(buffer)+0x1a)
|
||||
|
||||
|
||||
extern unsigned char DM_ACT[];
|
||||
#define DM_ACT_SIZE 0x55
|
||||
#define QETH_DM_ACT_DEST_ADDR(buffer) (buffer+0x2c)
|
||||
#define QETH_DM_ACT_CONNECTION_TOKEN(buffer) (buffer+0x51)
|
||||
|
||||
|
||||
|
||||
#define QETH_TRANSPORT_HEADER_SEQ_NO(buffer) (buffer+4)
|
||||
#define QETH_PDU_HEADER_SEQ_NO(buffer) (buffer+0x1c)
|
||||
#define QETH_PDU_HEADER_ACK_SEQ_NO(buffer) (buffer+0x20)
|
||||
|
||||
extern unsigned char IDX_ACTIVATE_READ[];
|
||||
extern unsigned char IDX_ACTIVATE_WRITE[];
|
||||
|
||||
#define IDX_ACTIVATE_SIZE 0x22
|
||||
#define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c)
|
||||
#define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80)
|
||||
#define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10)
|
||||
#define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer+0x16)
|
||||
#define QETH_IDX_ACT_QDIO_DEV_CUA(buffer) (buffer+0x1e)
|
||||
#define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20)
|
||||
#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
|
||||
#define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
|
||||
|
||||
#define PDU_ENCAPSULATION(buffer) \
|
||||
(buffer + *(buffer + (*(buffer+0x0b)) + \
|
||||
*(buffer + *(buffer+0x0b)+0x11) +0x07))
|
||||
|
||||
#define IS_IPA(buffer) \
|
||||
((buffer) && \
|
||||
( *(buffer + ((*(buffer+0x0b))+4) )==0xc1) )
|
||||
|
||||
#define ADDR_FRAME_TYPE_DIX 1
|
||||
#define ADDR_FRAME_TYPE_802_3 2
|
||||
#define ADDR_FRAME_TYPE_TR_WITHOUT_SR 0x10
|
||||
#define ADDR_FRAME_TYPE_TR_WITH_SR 0x20
|
||||
|
||||
#endif
|
495
drivers/s390/net/qeth_proc.c
Normale Datei
495
drivers/s390/net/qeth_proc.c
Normale Datei
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
*
|
||||
* linux/drivers/s390/net/qeth_fs.c ($Revision: 1.13 $)
|
||||
*
|
||||
* Linux on zSeries OSA Express and HiperSockets support
|
||||
* This file contains code related to procfs.
|
||||
*
|
||||
* Copyright 2000,2003 IBM Corporation
|
||||
*
|
||||
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rwsem.h>
|
||||
|
||||
#include "qeth.h"
|
||||
#include "qeth_mpc.h"
|
||||
#include "qeth_fs.h"
|
||||
|
||||
const char *VERSION_QETH_PROC_C = "$Revision: 1.13 $";
|
||||
|
||||
/***** /proc/qeth *****/
|
||||
#define QETH_PROCFILE_NAME "qeth"
|
||||
static struct proc_dir_entry *qeth_procfile;
|
||||
|
||||
static void *
|
||||
qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
|
||||
{
|
||||
struct list_head *next_card = NULL;
|
||||
int i = 0;
|
||||
|
||||
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
|
||||
if (*offset == 0)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
/* get card at pos *offset */
|
||||
list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices)
|
||||
if (++i == *offset)
|
||||
return next_card;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
qeth_procfile_seq_stop(struct seq_file *s, void* it)
|
||||
{
|
||||
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
}
|
||||
|
||||
static void *
|
||||
qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
|
||||
{
|
||||
struct list_head *next_card = NULL;
|
||||
struct list_head *current_card;
|
||||
|
||||
if (it == SEQ_START_TOKEN) {
|
||||
next_card = qeth_ccwgroup_driver.driver.devices.next;
|
||||
if (next_card->next == next_card) /* list empty */
|
||||
return NULL;
|
||||
(*offset)++;
|
||||
} else {
|
||||
current_card = (struct list_head *)it;
|
||||
if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
|
||||
return NULL; /* end of list reached */
|
||||
next_card = current_card->next;
|
||||
(*offset)++;
|
||||
}
|
||||
|
||||
return next_card;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
qeth_get_router_str(struct qeth_card *card, int ipv)
|
||||
{
|
||||
int routing_type = 0;
|
||||
|
||||
if (ipv == 4){
|
||||
routing_type = card->options.route4.type;
|
||||
} else {
|
||||
#ifdef CONFIG_QETH_IPV6
|
||||
routing_type = card->options.route6.type;
|
||||
#else
|
||||
return "n/a";
|
||||
#endif /* CONFIG_QETH_IPV6 */
|
||||
}
|
||||
|
||||
if (routing_type == PRIMARY_ROUTER)
|
||||
return "pri";
|
||||
else if (routing_type == SECONDARY_ROUTER)
|
||||
return "sec";
|
||||
else if (routing_type == MULTICAST_ROUTER) {
|
||||
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
|
||||
return "mc+";
|
||||
return "mc";
|
||||
} else if (routing_type == PRIMARY_CONNECTOR) {
|
||||
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
|
||||
return "p+c";
|
||||
return "p.c";
|
||||
} else if (routing_type == SECONDARY_CONNECTOR) {
|
||||
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
|
||||
return "s+c";
|
||||
return "s.c";
|
||||
} else if (routing_type == NO_ROUTER)
|
||||
return "no";
|
||||
else
|
||||
return "unk";
|
||||
}
|
||||
|
||||
static int
|
||||
qeth_procfile_seq_show(struct seq_file *s, void *it)
|
||||
{
|
||||
struct device *device;
|
||||
struct qeth_card *card;
|
||||
char tmp[12]; /* for qeth_get_prioq_str */
|
||||
|
||||
if (it == SEQ_START_TOKEN){
|
||||
seq_printf(s, "devices CHPID interface "
|
||||
"cardtype port chksum prio-q'ing rtr4 "
|
||||
"rtr6 fsz cnt\n");
|
||||
seq_printf(s, "-------------------------- ----- ---------- "
|
||||
"-------------- ---- ------ ---------- ---- "
|
||||
"---- ----- -----\n");
|
||||
} else {
|
||||
device = list_entry(it, struct device, driver_list);
|
||||
card = device->driver_data;
|
||||
seq_printf(s, "%s/%s/%s x%02X %-10s %-14s %-4i ",
|
||||
CARD_RDEV_ID(card),
|
||||
CARD_WDEV_ID(card),
|
||||
CARD_DDEV_ID(card),
|
||||
card->info.chpid,
|
||||
QETH_CARD_IFNAME(card),
|
||||
qeth_get_cardname_short(card),
|
||||
card->info.portno);
|
||||
if (card->lan_online)
|
||||
seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n",
|
||||
qeth_get_checksum_str(card),
|
||||
qeth_get_prioq_str(card, tmp),
|
||||
qeth_get_router_str(card, 4),
|
||||
qeth_get_router_str(card, 6),
|
||||
qeth_get_bufsize_str(card),
|
||||
card->qdio.in_buf_pool.buf_count);
|
||||
else
|
||||
seq_printf(s, " +++ LAN OFFLINE +++\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations qeth_procfile_seq_ops = {
|
||||
.start = qeth_procfile_seq_start,
|
||||
.stop = qeth_procfile_seq_stop,
|
||||
.next = qeth_procfile_seq_next,
|
||||
.show = qeth_procfile_seq_show,
|
||||
};
|
||||
|
||||
static int
|
||||
qeth_procfile_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &qeth_procfile_seq_ops);
|
||||
}
|
||||
|
||||
static struct file_operations qeth_procfile_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = qeth_procfile_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/***** /proc/qeth_perf *****/
|
||||
#define QETH_PERF_PROCFILE_NAME "qeth_perf"
|
||||
static struct proc_dir_entry *qeth_perf_procfile;
|
||||
|
||||
#ifdef CONFIG_QETH_PERF_STATS
|
||||
|
||||
static void *
|
||||
qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset)
|
||||
{
|
||||
struct list_head *next_card = NULL;
|
||||
int i = 0;
|
||||
|
||||
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
/* get card at pos *offset */
|
||||
list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
|
||||
if (i == *offset)
|
||||
return next_card;
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
qeth_perf_procfile_seq_stop(struct seq_file *s, void* it)
|
||||
{
|
||||
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
}
|
||||
|
||||
static void *
|
||||
qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
|
||||
{
|
||||
struct list_head *current_card = (struct list_head *)it;
|
||||
|
||||
if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
|
||||
return NULL; /* end of list reached */
|
||||
(*offset)++;
|
||||
return current_card->next;
|
||||
}
|
||||
|
||||
static int
|
||||
qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
|
||||
{
|
||||
struct device *device;
|
||||
struct qeth_card *card;
|
||||
|
||||
device = list_entry(it, struct device, driver_list);
|
||||
card = device->driver_data;
|
||||
seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
|
||||
CARD_RDEV_ID(card),
|
||||
CARD_WDEV_ID(card),
|
||||
CARD_DDEV_ID(card),
|
||||
QETH_CARD_IFNAME(card)
|
||||
);
|
||||
seq_printf(s, " Skb's/buffers received : %li/%i\n"
|
||||
" Skb's/buffers sent : %li/%i\n\n",
|
||||
card->stats.rx_packets, card->perf_stats.bufs_rec,
|
||||
card->stats.tx_packets, card->perf_stats.bufs_sent
|
||||
);
|
||||
seq_printf(s, " Skb's/buffers sent without packing : %li/%i\n"
|
||||
" Skb's/buffers sent with packing : %i/%i\n\n",
|
||||
card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
|
||||
card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
|
||||
card->perf_stats.skbs_sent_pack,
|
||||
card->perf_stats.bufs_sent_pack
|
||||
);
|
||||
seq_printf(s, " Skbs sent in SG mode : %i\n"
|
||||
" Skb fragments sent in SG mode : %i\n\n",
|
||||
card->perf_stats.sg_skbs_sent,
|
||||
card->perf_stats.sg_frags_sent);
|
||||
seq_printf(s, " large_send tx (in Kbytes) : %i\n"
|
||||
" large_send count : %i\n\n",
|
||||
card->perf_stats.large_send_bytes >> 10,
|
||||
card->perf_stats.large_send_cnt);
|
||||
seq_printf(s, " Packing state changes no pkg.->packing : %i/%i\n"
|
||||
" Watermarks L/H : %i/%i\n"
|
||||
" Current buffer usage (outbound q's) : "
|
||||
"%i/%i/%i/%i\n\n",
|
||||
card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
|
||||
QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
|
||||
atomic_read(&card->qdio.out_qs[0]->used_buffers),
|
||||
(card->qdio.no_out_queues > 1)?
|
||||
atomic_read(&card->qdio.out_qs[1]->used_buffers)
|
||||
: 0,
|
||||
(card->qdio.no_out_queues > 2)?
|
||||
atomic_read(&card->qdio.out_qs[2]->used_buffers)
|
||||
: 0,
|
||||
(card->qdio.no_out_queues > 3)?
|
||||
atomic_read(&card->qdio.out_qs[3]->used_buffers)
|
||||
: 0
|
||||
);
|
||||
seq_printf(s, " Inbound handler time (in us) : %i\n"
|
||||
" Inbound handler count : %i\n"
|
||||
" Inbound do_QDIO time (in us) : %i\n"
|
||||
" Inbound do_QDIO count : %i\n\n"
|
||||
" Outbound handler time (in us) : %i\n"
|
||||
" Outbound handler count : %i\n\n"
|
||||
" Outbound time (in us, incl QDIO) : %i\n"
|
||||
" Outbound count : %i\n"
|
||||
" Outbound do_QDIO time (in us) : %i\n"
|
||||
" Outbound do_QDIO count : %i\n\n",
|
||||
card->perf_stats.inbound_time,
|
||||
card->perf_stats.inbound_cnt,
|
||||
card->perf_stats.inbound_do_qdio_time,
|
||||
card->perf_stats.inbound_do_qdio_cnt,
|
||||
card->perf_stats.outbound_handler_time,
|
||||
card->perf_stats.outbound_handler_cnt,
|
||||
card->perf_stats.outbound_time,
|
||||
card->perf_stats.outbound_cnt,
|
||||
card->perf_stats.outbound_do_qdio_time,
|
||||
card->perf_stats.outbound_do_qdio_cnt
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations qeth_perf_procfile_seq_ops = {
|
||||
.start = qeth_perf_procfile_seq_start,
|
||||
.stop = qeth_perf_procfile_seq_stop,
|
||||
.next = qeth_perf_procfile_seq_next,
|
||||
.show = qeth_perf_procfile_seq_show,
|
||||
};
|
||||
|
||||
static int
|
||||
qeth_perf_procfile_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &qeth_perf_procfile_seq_ops);
|
||||
}
|
||||
|
||||
static struct file_operations qeth_perf_procfile_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = qeth_perf_procfile_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
#define qeth_perf_procfile_created qeth_perf_procfile
|
||||
#else
|
||||
#define qeth_perf_procfile_created 1
|
||||
#endif /* CONFIG_QETH_PERF_STATS */
|
||||
|
||||
/***** /proc/qeth_ipa_takeover *****/
|
||||
#define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover"
|
||||
static struct proc_dir_entry *qeth_ipato_procfile;
|
||||
|
||||
static void *
|
||||
qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
|
||||
{
|
||||
struct list_head *next_card = NULL;
|
||||
int i = 0;
|
||||
|
||||
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
/* TODO: finish this */
|
||||
/*
|
||||
* maybe SEQ_SATRT_TOKEN can be returned for offset 0
|
||||
* output driver settings then;
|
||||
* else output setting for respective card
|
||||
*/
|
||||
/* get card at pos *offset */
|
||||
list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
|
||||
if (i == *offset)
|
||||
return next_card;
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
|
||||
{
|
||||
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
}
|
||||
|
||||
static void *
|
||||
qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
|
||||
{
|
||||
struct list_head *current_card = (struct list_head *)it;
|
||||
|
||||
/* TODO: finish this */
|
||||
/*
|
||||
* maybe SEQ_SATRT_TOKEN can be returned for offset 0
|
||||
* output driver settings then;
|
||||
* else output setting for respective card
|
||||
*/
|
||||
if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
|
||||
return NULL; /* end of list reached */
|
||||
(*offset)++;
|
||||
return current_card->next;
|
||||
}
|
||||
|
||||
static int
|
||||
qeth_ipato_procfile_seq_show(struct seq_file *s, void *it)
|
||||
{
|
||||
struct device *device;
|
||||
struct qeth_card *card;
|
||||
|
||||
/* TODO: finish this */
|
||||
/*
|
||||
* maybe SEQ_SATRT_TOKEN can be returned for offset 0
|
||||
* output driver settings then;
|
||||
* else output setting for respective card
|
||||
*/
|
||||
device = list_entry(it, struct device, driver_list);
|
||||
card = device->driver_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations qeth_ipato_procfile_seq_ops = {
|
||||
.start = qeth_ipato_procfile_seq_start,
|
||||
.stop = qeth_ipato_procfile_seq_stop,
|
||||
.next = qeth_ipato_procfile_seq_next,
|
||||
.show = qeth_ipato_procfile_seq_show,
|
||||
};
|
||||
|
||||
static int
|
||||
qeth_ipato_procfile_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &qeth_ipato_procfile_seq_ops);
|
||||
}
|
||||
|
||||
static struct file_operations qeth_ipato_procfile_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = qeth_ipato_procfile_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
int __init
|
||||
qeth_create_procfs_entries(void)
|
||||
{
|
||||
qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
|
||||
S_IFREG | 0444, NULL);
|
||||
if (qeth_procfile)
|
||||
qeth_procfile->proc_fops = &qeth_procfile_fops;
|
||||
|
||||
#ifdef CONFIG_QETH_PERF_STATS
|
||||
qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
|
||||
S_IFREG | 0444, NULL);
|
||||
if (qeth_perf_procfile)
|
||||
qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
|
||||
#endif /* CONFIG_QETH_PERF_STATS */
|
||||
|
||||
qeth_ipato_procfile = create_proc_entry(QETH_IPATO_PROCFILE_NAME,
|
||||
S_IFREG | 0444, NULL);
|
||||
if (qeth_ipato_procfile)
|
||||
qeth_ipato_procfile->proc_fops = &qeth_ipato_procfile_fops;
|
||||
|
||||
if (qeth_procfile &&
|
||||
qeth_ipato_procfile &&
|
||||
qeth_perf_procfile_created)
|
||||
return 0;
|
||||
else
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void __exit
|
||||
qeth_remove_procfs_entries(void)
|
||||
{
|
||||
if (qeth_procfile)
|
||||
remove_proc_entry(QETH_PROCFILE_NAME, NULL);
|
||||
if (qeth_perf_procfile)
|
||||
remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
|
||||
if (qeth_ipato_procfile)
|
||||
remove_proc_entry(QETH_IPATO_PROCFILE_NAME, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* ONLY FOR DEVELOPMENT! -> make it as module */
|
||||
/*
|
||||
static void
|
||||
qeth_create_sysfs_entries(void)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
|
||||
list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
|
||||
driver_list)
|
||||
qeth_create_device_attributes(dev);
|
||||
|
||||
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
}
|
||||
|
||||
static void
|
||||
qeth_remove_sysfs_entries(void)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
|
||||
list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
|
||||
driver_list)
|
||||
qeth_remove_device_attributes(dev);
|
||||
|
||||
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
|
||||
}
|
||||
|
||||
static int __init
|
||||
qeth_fs_init(void)
|
||||
{
|
||||
printk(KERN_INFO "qeth_fs_init\n");
|
||||
qeth_create_procfs_entries();
|
||||
qeth_create_sysfs_entries();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
qeth_fs_exit(void)
|
||||
{
|
||||
printk(KERN_INFO "qeth_fs_exit\n");
|
||||
qeth_remove_procfs_entries();
|
||||
qeth_remove_sysfs_entries();
|
||||
}
|
||||
|
||||
|
||||
module_init(qeth_fs_init);
|
||||
module_exit(qeth_fs_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
*/
|
1788
drivers/s390/net/qeth_sys.c
Normale Datei
1788
drivers/s390/net/qeth_sys.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
285
drivers/s390/net/qeth_tso.c
Normale Datei
285
drivers/s390/net/qeth_tso.c
Normale Datei
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* linux/drivers/s390/net/qeth_tso.c ($Revision: 1.6 $)
|
||||
*
|
||||
* Header file for qeth TCP Segmentation Offload support.
|
||||
*
|
||||
* Copyright 2004 IBM Corporation
|
||||
*
|
||||
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
|
||||
*
|
||||
* $Revision: 1.6 $ $Date: 2005/03/24 09:04:18 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include "qeth.h"
|
||||
#include "qeth_mpc.h"
|
||||
#include "qeth_tso.h"
|
||||
|
||||
/**
|
||||
* skb already partially prepared
|
||||
* classic qdio header in skb->data
|
||||
* */
|
||||
static inline struct qeth_hdr_tso *
|
||||
qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "tsoprsk");
|
||||
rc = qeth_realloc_headroom(card, skb,sizeof(struct qeth_hdr_ext_tso));
|
||||
if (rc)
|
||||
return NULL;
|
||||
|
||||
return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_ext_tso));
|
||||
}
|
||||
|
||||
/**
|
||||
* fill header for a TSO packet
|
||||
*/
|
||||
static inline void
|
||||
qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
|
||||
{
|
||||
struct qeth_hdr_tso *hdr;
|
||||
struct tcphdr *tcph;
|
||||
struct iphdr *iph;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "tsofhdr");
|
||||
|
||||
hdr = (struct qeth_hdr_tso *) skb->data;
|
||||
iph = skb->nh.iph;
|
||||
tcph = skb->h.th;
|
||||
/*fix header to TSO values ...*/
|
||||
hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
|
||||
/*set values which are fix for the first approach ...*/
|
||||
hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
|
||||
hdr->ext.imb_hdr_no = 1;
|
||||
hdr->ext.hdr_type = 1;
|
||||
hdr->ext.hdr_version = 1;
|
||||
hdr->ext.hdr_len = 28;
|
||||
/*insert non-fix values */
|
||||
hdr->ext.mss = skb_shinfo(skb)->tso_size;
|
||||
hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
|
||||
hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
|
||||
sizeof(struct qeth_hdr_tso));
|
||||
}
|
||||
|
||||
/**
|
||||
* change some header values as requested by hardware
|
||||
*/
|
||||
static inline void
|
||||
qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct ipv6hdr *ip6h;
|
||||
struct tcphdr *tcph;
|
||||
|
||||
iph = skb->nh.iph;
|
||||
ip6h = skb->nh.ipv6h;
|
||||
tcph = skb->h.th;
|
||||
|
||||
tcph->check = 0;
|
||||
if (skb->protocol == ETH_P_IPV6) {
|
||||
ip6h->payload_len = 0;
|
||||
tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
|
||||
0, IPPROTO_TCP, 0);
|
||||
return;
|
||||
}
|
||||
/*OSA want us to set these values ...*/
|
||||
tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
|
||||
0, IPPROTO_TCP, 0);
|
||||
iph->tot_len = 0;
|
||||
iph->check = 0;
|
||||
}
|
||||
|
||||
static inline struct qeth_hdr_tso *
|
||||
qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
|
||||
int ipv, int cast_type)
|
||||
{
|
||||
struct qeth_hdr_tso *hdr;
|
||||
int rc = 0;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "tsoprep");
|
||||
|
||||
/*get headroom for tso qdio header */
|
||||
hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
|
||||
if (hdr == NULL) {
|
||||
QETH_DBF_TEXT_(trace, 4, "2err%d", rc);
|
||||
return NULL;
|
||||
}
|
||||
memset(hdr, 0, sizeof(struct qeth_hdr_tso));
|
||||
/*fill first 32 bytes of qdio header as used
|
||||
*FIXME: TSO has two struct members
|
||||
* with different names but same size
|
||||
* */
|
||||
qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
|
||||
qeth_tso_fill_header(card, skb);
|
||||
qeth_tso_set_tcpip_header(card, skb);
|
||||
return hdr;
|
||||
}
|
||||
|
||||
static inline int
|
||||
qeth_tso_get_queue_buffer(struct qeth_qdio_out_q *queue)
|
||||
{
|
||||
struct qeth_qdio_out_buffer *buffer;
|
||||
int flush_cnt = 0;
|
||||
|
||||
QETH_DBF_TEXT(trace, 5, "tsobuf");
|
||||
|
||||
/* force to non-packing*/
|
||||
if (queue->do_pack)
|
||||
queue->do_pack = 0;
|
||||
buffer = &queue->bufs[queue->next_buf_to_fill];
|
||||
/* get a new buffer if current is already in use*/
|
||||
if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
|
||||
(buffer->next_element_to_fill > 0)) {
|
||||
atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
|
||||
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
|
||||
QDIO_MAX_BUFFERS_PER_Q;
|
||||
flush_cnt++;
|
||||
}
|
||||
return flush_cnt;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__qeth_tso_fill_buffer_frag(struct qeth_qdio_out_buffer *buf,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct skb_frag_struct *frag;
|
||||
struct qdio_buffer *buffer;
|
||||
int fragno, cnt, element;
|
||||
unsigned long addr;
|
||||
|
||||
QETH_DBF_TEXT(trace, 6, "tsfilfrg");
|
||||
|
||||
/*initialize variables ...*/
|
||||
fragno = skb_shinfo(skb)->nr_frags;
|
||||
buffer = buf->buffer;
|
||||
element = buf->next_element_to_fill;
|
||||
/*fill buffer elements .....*/
|
||||
for (cnt = 0; cnt < fragno; cnt++) {
|
||||
frag = &skb_shinfo(skb)->frags[cnt];
|
||||
addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
|
||||
frag->page_offset;
|
||||
buffer->element[element].addr = (char *)addr;
|
||||
buffer->element[element].length = frag->size;
|
||||
if (cnt < (fragno - 1))
|
||||
buffer->element[element].flags =
|
||||
SBAL_FLAGS_MIDDLE_FRAG;
|
||||
else
|
||||
buffer->element[element].flags =
|
||||
SBAL_FLAGS_LAST_FRAG;
|
||||
element++;
|
||||
}
|
||||
buf->next_element_to_fill = element;
|
||||
}
|
||||
|
||||
static inline int
|
||||
qeth_tso_fill_buffer(struct qeth_qdio_out_buffer *buf,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
int length, length_here, element;
|
||||
int hdr_len;
|
||||
struct qdio_buffer *buffer;
|
||||
struct qeth_hdr_tso *hdr;
|
||||
char *data;
|
||||
|
||||
QETH_DBF_TEXT(trace, 3, "tsfilbuf");
|
||||
|
||||
/*increment user count and queue skb ...*/
|
||||
atomic_inc(&skb->users);
|
||||
skb_queue_tail(&buf->skb_list, skb);
|
||||
|
||||
/*initialize all variables...*/
|
||||
buffer = buf->buffer;
|
||||
hdr = (struct qeth_hdr_tso *)skb->data;
|
||||
hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
|
||||
data = skb->data + hdr_len;
|
||||
length = skb->len - hdr_len;
|
||||
element = buf->next_element_to_fill;
|
||||
/*fill first buffer entry only with header information */
|
||||
buffer->element[element].addr = skb->data;
|
||||
buffer->element[element].length = hdr_len;
|
||||
buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
|
||||
buf->next_element_to_fill++;
|
||||
|
||||
if (skb_shinfo(skb)->nr_frags > 0) {
|
||||
__qeth_tso_fill_buffer_frag(buf, skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*start filling buffer entries ...*/
|
||||
element++;
|
||||
while (length > 0) {
|
||||
/* length_here is the remaining amount of data in this page */
|
||||
length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
|
||||
if (length < length_here)
|
||||
length_here = length;
|
||||
buffer->element[element].addr = data;
|
||||
buffer->element[element].length = length_here;
|
||||
length -= length_here;
|
||||
if (!length)
|
||||
buffer->element[element].flags =
|
||||
SBAL_FLAGS_LAST_FRAG;
|
||||
else
|
||||
buffer->element[element].flags =
|
||||
SBAL_FLAGS_MIDDLE_FRAG;
|
||||
data += length_here;
|
||||
element++;
|
||||
}
|
||||
/*set the buffer to primed ...*/
|
||||
buf->next_element_to_fill = element;
|
||||
out:
|
||||
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
qeth_tso_send_packet(struct qeth_card *card, struct sk_buff *skb,
|
||||
struct qeth_qdio_out_q *queue, int ipv, int cast_type)
|
||||
{
|
||||
int flush_cnt = 0;
|
||||
struct qeth_hdr_tso *hdr;
|
||||
struct qeth_qdio_out_buffer *buffer;
|
||||
int start_index;
|
||||
|
||||
QETH_DBF_TEXT(trace, 3, "tsosend");
|
||||
|
||||
if (!(hdr = qeth_tso_prepare_packet(card, skb, ipv, cast_type)))
|
||||
return -ENOMEM;
|
||||
/*check if skb fits in one SBAL ...*/
|
||||
if (!(qeth_get_elements_no(card, (void*)hdr, skb)))
|
||||
return -EINVAL;
|
||||
/*lock queue, force switching to non-packing and send it ...*/
|
||||
while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
|
||||
QETH_OUT_Q_LOCKED,
|
||||
&queue->state));
|
||||
start_index = queue->next_buf_to_fill;
|
||||
buffer = &queue->bufs[queue->next_buf_to_fill];
|
||||
/*check if card is too busy ...*/
|
||||
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
|
||||
card->stats.tx_dropped++;
|
||||
goto out;
|
||||
}
|
||||
/*let's force to non-packing and get a new SBAL*/
|
||||
flush_cnt += qeth_tso_get_queue_buffer(queue);
|
||||
buffer = &queue->bufs[queue->next_buf_to_fill];
|
||||
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
|
||||
card->stats.tx_dropped++;
|
||||
goto out;
|
||||
}
|
||||
flush_cnt += qeth_tso_fill_buffer(buffer, skb);
|
||||
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
|
||||
QDIO_MAX_BUFFERS_PER_Q;
|
||||
out:
|
||||
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
|
||||
if (flush_cnt)
|
||||
qeth_flush_buffers(queue, 0, start_index, flush_cnt);
|
||||
/*do some statistics */
|
||||
card->stats.tx_packets++;
|
||||
card->stats.tx_bytes += skb->len;
|
||||
return 0;
|
||||
}
|
58
drivers/s390/net/qeth_tso.h
Normale Datei
58
drivers/s390/net/qeth_tso.h
Normale Datei
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* linux/drivers/s390/net/qeth_tso.h ($Revision: 1.4 $)
|
||||
*
|
||||
* Header file for qeth TCP Segmentation Offload support.
|
||||
*
|
||||
* Copyright 2004 IBM Corporation
|
||||
*
|
||||
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
|
||||
*
|
||||
* $Revision: 1.4 $ $Date: 2005/03/24 09:04:18 $
|
||||
*
|
||||
*/
|
||||
#ifndef __QETH_TSO_H__
|
||||
#define __QETH_TSO_H__
|
||||
|
||||
|
||||
extern int
|
||||
qeth_tso_send_packet(struct qeth_card *, struct sk_buff *,
|
||||
struct qeth_qdio_out_q *, int , int);
|
||||
|
||||
struct qeth_hdr_ext_tso {
|
||||
__u16 hdr_tot_len;
|
||||
__u8 imb_hdr_no;
|
||||
__u8 reserved;
|
||||
__u8 hdr_type;
|
||||
__u8 hdr_version;
|
||||
__u16 hdr_len;
|
||||
__u32 payload_len;
|
||||
__u16 mss;
|
||||
__u16 dg_hdr_len;
|
||||
__u8 padding[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct qeth_hdr_tso {
|
||||
struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/
|
||||
struct qeth_hdr_ext_tso ext;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*some helper functions*/
|
||||
|
||||
static inline int
|
||||
qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
|
||||
{
|
||||
int elements_needed = 0;
|
||||
|
||||
if (skb_shinfo(skb)->nr_frags > 0)
|
||||
elements_needed = (skb_shinfo(skb)->nr_frags + 1);
|
||||
if (elements_needed == 0 )
|
||||
elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
|
||||
+ skb->len) >> PAGE_SHIFT);
|
||||
if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
|
||||
PRINT_ERR("qeth_do_send_packet: invalid size of "
|
||||
"IP packet. Discarded.");
|
||||
return 0;
|
||||
}
|
||||
return elements_needed;
|
||||
}
|
||||
#endif /* __QETH_TSO_H__ */
|
180
drivers/s390/net/smsgiucv.c
Normale Datei
180
drivers/s390/net/smsgiucv.c
Normale Datei
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* IUCV special message driver
|
||||
*
|
||||
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
||||
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/cpcmd.h>
|
||||
#include <asm/ebcdic.h>
|
||||
|
||||
#include "iucv.h"
|
||||
|
||||
struct smsg_callback {
|
||||
struct list_head list;
|
||||
char *prefix;
|
||||
int len;
|
||||
void (*callback)(char *str);
|
||||
};
|
||||
|
||||
MODULE_AUTHOR
|
||||
("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
|
||||
MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
|
||||
|
||||
static iucv_handle_t smsg_handle;
|
||||
static unsigned short smsg_pathid;
|
||||
static DEFINE_SPINLOCK(smsg_list_lock);
|
||||
static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
|
||||
|
||||
static void
|
||||
smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
|
||||
{
|
||||
struct smsg_callback *cb;
|
||||
unsigned char *msg;
|
||||
unsigned short len;
|
||||
int rc;
|
||||
|
||||
len = eib->ln1msg2.ipbfln1f;
|
||||
msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA);
|
||||
if (!msg) {
|
||||
iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls);
|
||||
return;
|
||||
}
|
||||
rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
|
||||
msg, len, 0, 0, 0);
|
||||
if (rc == 0) {
|
||||
msg[len] = 0;
|
||||
EBCASC(msg, len);
|
||||
spin_lock(&smsg_list_lock);
|
||||
list_for_each_entry(cb, &smsg_list, list)
|
||||
if (strncmp(msg + 8, cb->prefix, cb->len) == 0) {
|
||||
cb->callback(msg + 8);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&smsg_list_lock);
|
||||
}
|
||||
kfree(msg);
|
||||
}
|
||||
|
||||
static iucv_interrupt_ops_t smsg_ops = {
|
||||
.ConnectionComplete = smsg_connection_complete,
|
||||
.MessagePending = smsg_message_pending,
|
||||
};
|
||||
|
||||
static struct device_driver smsg_driver = {
|
||||
.name = "SMSGIUCV",
|
||||
.bus = &iucv_bus,
|
||||
};
|
||||
|
||||
int
|
||||
smsg_register_callback(char *prefix, void (*callback)(char *str))
|
||||
{
|
||||
struct smsg_callback *cb;
|
||||
|
||||
cb = kmalloc(sizeof(struct smsg_callback), GFP_KERNEL);
|
||||
if (!cb)
|
||||
return -ENOMEM;
|
||||
cb->prefix = prefix;
|
||||
cb->len = strlen(prefix);
|
||||
cb->callback = callback;
|
||||
spin_lock(&smsg_list_lock);
|
||||
list_add_tail(&cb->list, &smsg_list);
|
||||
spin_unlock(&smsg_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
smsg_unregister_callback(char *prefix, void (*callback)(char *str))
|
||||
{
|
||||
struct smsg_callback *cb, *tmp;
|
||||
|
||||
spin_lock(&smsg_list_lock);
|
||||
cb = 0;
|
||||
list_for_each_entry(tmp, &smsg_list, list)
|
||||
if (tmp->callback == callback &&
|
||||
strcmp(tmp->prefix, prefix) == 0) {
|
||||
cb = tmp;
|
||||
list_del(&cb->list);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&smsg_list_lock);
|
||||
kfree(cb);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
smsg_exit(void)
|
||||
{
|
||||
if (smsg_handle > 0) {
|
||||
cpcmd("SET SMSG OFF", 0, 0);
|
||||
iucv_sever(smsg_pathid, 0);
|
||||
iucv_unregister_program(smsg_handle);
|
||||
driver_unregister(&smsg_driver);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int __init
|
||||
smsg_init(void)
|
||||
{
|
||||
static unsigned char pgmmask[24] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = driver_register(&smsg_driver);
|
||||
if (rc != 0) {
|
||||
printk(KERN_ERR "SMSGIUCV: failed to register driver.\n");
|
||||
return rc;
|
||||
}
|
||||
smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ",
|
||||
pgmmask, &smsg_ops, 0);
|
||||
if (!smsg_handle) {
|
||||
printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
|
||||
driver_unregister(&smsg_driver);
|
||||
return -EIO; /* better errno ? */
|
||||
}
|
||||
rc = iucv_connect (&smsg_pathid, 1, 0, "*MSG ", 0, 0, 0, 0,
|
||||
smsg_handle, 0);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
|
||||
iucv_unregister_program(smsg_handle);
|
||||
driver_unregister(&smsg_driver);
|
||||
smsg_handle = 0;
|
||||
return -EIO;
|
||||
}
|
||||
cpcmd("SET SMSG IUCV", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(smsg_init);
|
||||
module_exit(smsg_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(smsg_register_callback);
|
||||
EXPORT_SYMBOL(smsg_unregister_callback);
|
10
drivers/s390/net/smsgiucv.h
Normale Datei
10
drivers/s390/net/smsgiucv.h
Normale Datei
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* IUCV special message driver
|
||||
*
|
||||
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
||||
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
|
||||
*/
|
||||
|
||||
int smsg_register_callback(char *, void (*)(char *));
|
||||
void smsg_unregister_callback(char *, void (*)(char *));
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren