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:
Linus Torvalds
2005-04-16 15:20:36 -07:00
Commit 1da177e4c3
17291 geänderte Dateien mit 6718755 neuen und 0 gelöschten Zeilen

108
drivers/s390/net/Kconfig Normale Datei
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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

Datei-Diff unterdrückt, da er zu groß ist Diff laden

335
drivers/s390/net/claw.h Normale Datei
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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

Datei-Diff unterdrückt, da er zu groß ist Diff laden

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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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

Datei-Diff unterdrückt, da er zu groß ist Diff laden

849
drivers/s390/net/iucv.h Normale Datei
Datei anzeigen

@@ -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

Datei-Diff unterdrückt, da er zu groß ist Diff laden

321
drivers/s390/net/lcs.h Normale Datei
Datei anzeigen

@@ -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

Datei-Diff unterdrückt, da er zu groß ist Diff laden

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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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

Datei-Diff unterdrückt, da er zu groß ist Diff laden

168
drivers/s390/net/qeth_mpc.c Normale Datei
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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

Datei-Diff unterdrückt, da er zu groß ist Diff laden

285
drivers/s390/net/qeth_tso.c Normale Datei
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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
Datei anzeigen

@@ -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 *));