ctcm: infrastructure for replaced ctc driver

ctcm driver supports the channel-to-channel connections of the
old ctc driver plus an additional MPC protocol to provide SNA
connectivity.

This new ctcm driver replaces the existing ctc driver.

Signed-off-by: Peter Tiedemann <ptiedem@de.ibm.com>
Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Peter Tiedemann 2008-02-08 00:03:49 +01:00 committed by Jeff Garzik
parent f423f73506
commit 293d984f0e
11 changed files with 7920 additions and 8 deletions

View File

@ -11,15 +11,17 @@ config LCS
To compile as a module, choose M. The module name is lcs.ko. To compile as a module, choose M. The module name is lcs.ko.
If you do not know what it is, it's safe to choose Y. If you do not know what it is, it's safe to choose Y.
config CTC config CTCM
tristate "CTC device support" tristate "CTC and MPC SNA device support"
depends on CCW && NETDEVICES depends on CCW && NETDEVICES
help help
Select this option if you want to use channel-to-channel Select this option if you want to use channel-to-channel
point-to-point networking on IBM System z. point-to-point networking on IBM System z.
This device driver supports real CTC coupling using ESCON. This device driver supports real CTC coupling using ESCON.
It also supports virtual CTCs when running under VM. It also supports virtual CTCs when running under VM.
To compile as a module, choose M. The module name is ctc.ko. This driver also supports channel-to-channel MPC SNA devices.
MPC is an SNA protocol device used by Communication Server for Linux.
To compile as a module, choose M. The module name is ctcm.ko.
To compile into the kernel, choose Y. To compile into the kernel, choose Y.
If you do not need any channel-to-channel connection, choose N. If you do not need any channel-to-channel connection, choose N.
@ -84,7 +86,7 @@ config QETH_VLAN
802.1q VLAN support in the qeth device driver. 802.1q VLAN support in the qeth device driver.
config CCWGROUP config CCWGROUP
tristate tristate
default (LCS || CTC || QETH) default (LCS || CTCM || QETH)
endmenu endmenu

View File

@ -2,11 +2,10 @@
# S/390 network devices # S/390 network devices
# #
ctc-objs := ctcmain.o ctcdbug.o ctcm-y += ctcm_main.o ctcm_fsms.o ctcm_mpc.o ctcm_sysfs.o ctcm_dbug.o
obj-$(CONFIG_CTCM) += ctcm.o fsm.o cu3088.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS) += lcs.o cu3088.o obj-$(CONFIG_LCS) += lcs.o cu3088.o
obj-$(CONFIG_CLAW) += claw.o cu3088.o obj-$(CONFIG_CLAW) += claw.o cu3088.o
qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o

View File

@ -0,0 +1,67 @@
/*
* drivers/s390/net/ctcm_dbug.c
*
* Copyright IBM Corp. 2001, 2007
* Authors: Peter Tiedemann (ptiedem@de.ibm.com)
*
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/sysctl.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include "ctcm_dbug.h"
/*
* Debug Facility Stuff
*/
DEFINE_PER_CPU(char[256], ctcm_dbf_txt_buf);
struct ctcm_dbf_info ctcm_dbf[CTCM_DBF_INFOS] = {
[CTCM_DBF_SETUP] = {"ctc_setup", 8, 1, 64, 5, NULL},
[CTCM_DBF_ERROR] = {"ctc_error", 8, 1, 64, 3, NULL},
[CTCM_DBF_TRACE] = {"ctc_trace", 8, 1, 64, 3, NULL},
[CTCM_DBF_MPC_SETUP] = {"mpc_setup", 8, 1, 64, 5, NULL},
[CTCM_DBF_MPC_ERROR] = {"mpc_error", 8, 1, 64, 3, NULL},
[CTCM_DBF_MPC_TRACE] = {"mpc_trace", 8, 1, 64, 3, NULL},
};
void ctcm_unregister_dbf_views(void)
{
int x;
for (x = 0; x < CTCM_DBF_INFOS; x++) {
debug_unregister(ctcm_dbf[x].id);
ctcm_dbf[x].id = NULL;
}
}
int ctcm_register_dbf_views(void)
{
int x;
for (x = 0; x < CTCM_DBF_INFOS; x++) {
/* register the areas */
ctcm_dbf[x].id = debug_register(ctcm_dbf[x].name,
ctcm_dbf[x].pages,
ctcm_dbf[x].areas,
ctcm_dbf[x].len);
if (ctcm_dbf[x].id == NULL) {
ctcm_unregister_dbf_views();
return -ENOMEM;
}
/* register a view */
debug_register_view(ctcm_dbf[x].id, &debug_hex_ascii_view);
/* set a passing level */
debug_set_level(ctcm_dbf[x].id, ctcm_dbf[x].level);
}
return 0;
}

View File

@ -0,0 +1,158 @@
/*
* drivers/s390/net/ctcm_dbug.h
*
* Copyright IBM Corp. 2001, 2007
* Authors: Peter Tiedemann (ptiedem@de.ibm.com)
*
*/
#ifndef _CTCM_DBUG_H_
#define _CTCM_DBUG_H_
/*
* Debug Facility stuff
*/
#include <asm/debug.h>
#ifdef DEBUG
#define do_debug 1
#else
#define do_debug 0
#endif
#ifdef DEBUGDATA
#define do_debug_data 1
#else
#define do_debug_data 0
#endif
#ifdef DEBUGCCW
#define do_debug_ccw 1
#else
#define do_debug_ccw 0
#endif
/* define dbf debug levels similar to kernel msg levels */
#define CTC_DBF_ALWAYS 0 /* always print this */
#define CTC_DBF_EMERG 0 /* system is unusable */
#define CTC_DBF_ALERT 1 /* action must be taken immediately */
#define CTC_DBF_CRIT 2 /* critical conditions */
#define CTC_DBF_ERROR 3 /* error conditions */
#define CTC_DBF_WARN 4 /* warning conditions */
#define CTC_DBF_NOTICE 5 /* normal but significant condition */
#define CTC_DBF_INFO 5 /* informational */
#define CTC_DBF_DEBUG 6 /* debug-level messages */
DECLARE_PER_CPU(char[256], ctcm_dbf_txt_buf);
enum ctcm_dbf_names {
CTCM_DBF_SETUP,
CTCM_DBF_ERROR,
CTCM_DBF_TRACE,
CTCM_DBF_MPC_SETUP,
CTCM_DBF_MPC_ERROR,
CTCM_DBF_MPC_TRACE,
CTCM_DBF_INFOS /* must be last element */
};
struct ctcm_dbf_info {
char name[DEBUG_MAX_NAME_LEN];
int pages;
int areas;
int len;
int level;
debug_info_t *id;
};
extern struct ctcm_dbf_info ctcm_dbf[CTCM_DBF_INFOS];
int ctcm_register_dbf_views(void);
void ctcm_unregister_dbf_views(void);
static inline const char *strtail(const char *s, int n)
{
int l = strlen(s);
return (l > n) ? s + (l - n) : s;
}
/* sort out levels early to avoid unnecessary sprintfs */
static inline int ctcm_dbf_passes(debug_info_t *dbf_grp, int level)
{
return (dbf_grp->level >= level);
}
#define CTCM_FUNTAIL strtail((char *)__func__, 16)
#define CTCM_DBF_TEXT(name, level, text) \
do { \
debug_text_event(ctcm_dbf[CTCM_DBF_##name].id, level, text); \
} while (0)
#define CTCM_DBF_HEX(name, level, addr, len) \
do { \
debug_event(ctcm_dbf[CTCM_DBF_##name].id, \
level, (void *)(addr), len); \
} while (0)
#define CTCM_DBF_TEXT_(name, level, text...) \
do { \
if (ctcm_dbf_passes(ctcm_dbf[CTCM_DBF_##name].id, level)) { \
char *ctcm_dbf_txt_buf = \
get_cpu_var(ctcm_dbf_txt_buf); \
sprintf(ctcm_dbf_txt_buf, text); \
debug_text_event(ctcm_dbf[CTCM_DBF_##name].id, \
level, ctcm_dbf_txt_buf); \
put_cpu_var(ctcm_dbf_txt_buf); \
} \
} while (0)
/*
* cat : one of {setup, mpc_setup, trace, mpc_trace, error, mpc_error}.
* dev : netdevice with valid name field.
* text: any text string.
*/
#define CTCM_DBF_DEV_NAME(cat, dev, text) \
do { \
CTCM_DBF_TEXT_(cat, CTC_DBF_INFO, "%s(%s) : %s", \
CTCM_FUNTAIL, dev->name, text); \
} while (0)
#define MPC_DBF_DEV_NAME(cat, dev, text) \
do { \
CTCM_DBF_TEXT_(MPC_##cat, CTC_DBF_INFO, "%s(%s) : %s", \
CTCM_FUNTAIL, dev->name, text); \
} while (0)
#define CTCMY_DBF_DEV_NAME(cat, dev, text) \
do { \
if (IS_MPCDEV(dev)) \
MPC_DBF_DEV_NAME(cat, dev, text); \
else \
CTCM_DBF_DEV_NAME(cat, dev, text); \
} while (0)
/*
* cat : one of {setup, mpc_setup, trace, mpc_trace, error, mpc_error}.
* dev : netdevice.
* text: any text string.
*/
#define CTCM_DBF_DEV(cat, dev, text) \
do { \
CTCM_DBF_TEXT_(cat, CTC_DBF_INFO, "%s(%p) : %s", \
CTCM_FUNTAIL, dev, text); \
} while (0)
#define MPC_DBF_DEV(cat, dev, text) \
do { \
CTCM_DBF_TEXT_(MPC_##cat, CTC_DBF_INFO, "%s(%p) : %s", \
CTCM_FUNTAIL, dev, text); \
} while (0)
#define CTCMY_DBF_DEV(cat, dev, text) \
do { \
if (IS_MPCDEV(dev)) \
MPC_DBF_DEV(cat, dev, text); \
else \
CTCM_DBF_DEV(cat, dev, text); \
} while (0)
#endif

2347
drivers/s390/net/ctcm_fsms.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,359 @@
/*
* drivers/s390/net/ctcm_fsms.h
*
* Copyright IBM Corp. 2001, 2007
* Authors: Fritz Elfert (felfert@millenux.com)
* Peter Tiedemann (ptiedem@de.ibm.com)
* MPC additions :
* Belinda Thompson (belindat@us.ibm.com)
* Andy Richter (richtera@us.ibm.com)
*/
#ifndef _CTCM_FSMS_H_
#define _CTCM_FSMS_H_
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/bitops.h>
#include <linux/signal.h>
#include <linux/string.h>
#include <linux/ip.h>
#include <linux/if_arp.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/ctype.h>
#include <net/dst.h>
#include <linux/io.h>
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
#include <linux/uaccess.h>
#include <asm/idals.h>
#include "fsm.h"
#include "cu3088.h"
#include "ctcm_main.h"
/*
* Definitions for the channel statemachine(s) for ctc and ctcmpc
*
* To allow better kerntyping, prefix-less definitions for channel states
* and channel events have been replaced :
* ch_event... -> ctc_ch_event...
* CH_EVENT... -> CTC_EVENT...
* ch_state... -> ctc_ch_state...
* CH_STATE... -> CTC_STATE...
*/
/*
* Events of the channel statemachine(s) for ctc and ctcmpc
*/
enum ctc_ch_events {
/*
* Events, representing return code of
* I/O operations (ccw_device_start, ccw_device_halt et al.)
*/
CTC_EVENT_IO_SUCCESS,
CTC_EVENT_IO_EBUSY,
CTC_EVENT_IO_ENODEV,
CTC_EVENT_IO_UNKNOWN,
CTC_EVENT_ATTNBUSY,
CTC_EVENT_ATTN,
CTC_EVENT_BUSY,
/*
* Events, representing unit-check
*/
CTC_EVENT_UC_RCRESET,
CTC_EVENT_UC_RSRESET,
CTC_EVENT_UC_TXTIMEOUT,
CTC_EVENT_UC_TXPARITY,
CTC_EVENT_UC_HWFAIL,
CTC_EVENT_UC_RXPARITY,
CTC_EVENT_UC_ZERO,
CTC_EVENT_UC_UNKNOWN,
/*
* Events, representing subchannel-check
*/
CTC_EVENT_SC_UNKNOWN,
/*
* Events, representing machine checks
*/
CTC_EVENT_MC_FAIL,
CTC_EVENT_MC_GOOD,
/*
* Event, representing normal IRQ
*/
CTC_EVENT_IRQ,
CTC_EVENT_FINSTAT,
/*
* Event, representing timer expiry.
*/
CTC_EVENT_TIMER,
/*
* Events, representing commands from upper levels.
*/
CTC_EVENT_START,
CTC_EVENT_STOP,
CTC_NR_EVENTS,
/*
* additional MPC events
*/
CTC_EVENT_SEND_XID = CTC_NR_EVENTS,
CTC_EVENT_RSWEEP_TIMER,
/*
* MUST be always the last element!!
*/
CTC_MPC_NR_EVENTS,
};
/*
* States of the channel statemachine(s) for ctc and ctcmpc.
*/
enum ctc_ch_states {
/*
* Channel not assigned to any device,
* initial state, direction invalid
*/
CTC_STATE_IDLE,
/*
* Channel assigned but not operating
*/
CTC_STATE_STOPPED,
CTC_STATE_STARTWAIT,
CTC_STATE_STARTRETRY,
CTC_STATE_SETUPWAIT,
CTC_STATE_RXINIT,
CTC_STATE_TXINIT,
CTC_STATE_RX,
CTC_STATE_TX,
CTC_STATE_RXIDLE,
CTC_STATE_TXIDLE,
CTC_STATE_RXERR,
CTC_STATE_TXERR,
CTC_STATE_TERM,
CTC_STATE_DTERM,
CTC_STATE_NOTOP,
CTC_NR_STATES, /* MUST be the last element of non-expanded states */
/*
* additional MPC states
*/
CH_XID0_PENDING = CTC_NR_STATES,
CH_XID0_INPROGRESS,
CH_XID7_PENDING,
CH_XID7_PENDING1,
CH_XID7_PENDING2,
CH_XID7_PENDING3,
CH_XID7_PENDING4,
CTC_MPC_NR_STATES, /* MUST be the last element of expanded mpc states */
};
extern const char *ctc_ch_event_names[];
extern const char *ctc_ch_state_names[];
void ctcm_ccw_check_rc(struct channel *ch, int rc, char *msg);
void ctcm_purge_skb_queue(struct sk_buff_head *q);
void fsm_action_nop(fsm_instance *fi, int event, void *arg);
/*
* ----- non-static actions for ctcm channel statemachine -----
*
*/
void ctcm_chx_txidle(fsm_instance *fi, int event, void *arg);
/*
* ----- FSM (state/event/action) of the ctcm channel statemachine -----
*/
extern const fsm_node ch_fsm[];
extern int ch_fsm_len;
/*
* ----- non-static actions for ctcmpc channel statemachine ----
*
*/
/* shared :
void ctcm_chx_txidle(fsm_instance * fi, int event, void *arg);
*/
void ctcmpc_chx_rxidle(fsm_instance *fi, int event, void *arg);
/*
* ----- FSM (state/event/action) of the ctcmpc channel statemachine -----
*/
extern const fsm_node ctcmpc_ch_fsm[];
extern int mpc_ch_fsm_len;
/*
* Definitions for the device interface statemachine for ctc and mpc
*/
/*
* States of the device interface statemachine.
*/
enum dev_states {
DEV_STATE_STOPPED,
DEV_STATE_STARTWAIT_RXTX,
DEV_STATE_STARTWAIT_RX,
DEV_STATE_STARTWAIT_TX,
DEV_STATE_STOPWAIT_RXTX,
DEV_STATE_STOPWAIT_RX,
DEV_STATE_STOPWAIT_TX,
DEV_STATE_RUNNING,
/*
* MUST be always the last element!!
*/
CTCM_NR_DEV_STATES
};
extern const char *dev_state_names[];
/*
* Events of the device interface statemachine.
* ctcm and ctcmpc
*/
enum dev_events {
DEV_EVENT_START,
DEV_EVENT_STOP,
DEV_EVENT_RXUP,
DEV_EVENT_TXUP,
DEV_EVENT_RXDOWN,
DEV_EVENT_TXDOWN,
DEV_EVENT_RESTART,
/*
* MUST be always the last element!!
*/
CTCM_NR_DEV_EVENTS
};
extern const char *dev_event_names[];
/*
* Actions for the device interface statemachine.
* ctc and ctcmpc
*/
/*
static void dev_action_start(fsm_instance * fi, int event, void *arg);
static void dev_action_stop(fsm_instance * fi, int event, void *arg);
static void dev_action_restart(fsm_instance *fi, int event, void *arg);
static void dev_action_chup(fsm_instance * fi, int event, void *arg);
static void dev_action_chdown(fsm_instance * fi, int event, void *arg);
*/
/*
* The (state/event/action) fsm table of the device interface statemachine.
* ctcm and ctcmpc
*/
extern const fsm_node dev_fsm[];
extern int dev_fsm_len;
/*
* Definitions for the MPC Group statemachine
*/
/*
* MPC Group Station FSM States
State Name When In This State
====================== =======================================
MPCG_STATE_RESET Initial State When Driver Loaded
We receive and send NOTHING
MPCG_STATE_INOP INOP Received.
Group level non-recoverable error
MPCG_STATE_READY XID exchanges for at least 1 write and
1 read channel have completed.
Group is ready for data transfer.
States from ctc_mpc_alloc_channel
==============================================================
MPCG_STATE_XID2INITW Awaiting XID2(0) Initiation
ATTN from other side will start
XID negotiations.
Y-side protocol only.
MPCG_STATE_XID2INITX XID2(0) negotiations are in progress.
At least 1, but not all, XID2(0)'s
have been received from partner.
MPCG_STATE_XID7INITW XID2(0) complete
No XID2(7)'s have yet been received.
XID2(7) negotiations pending.
MPCG_STATE_XID7INITX XID2(7) negotiations in progress.
At least 1, but not all, XID2(7)'s
have been received from partner.
MPCG_STATE_XID7INITF XID2(7) negotiations complete.
Transitioning to READY.
MPCG_STATE_READY Ready for Data Transfer.
States from ctc_mpc_establish_connectivity call
==============================================================
MPCG_STATE_XID0IOWAIT Initiating XID2(0) negotiations.
X-side protocol only.
ATTN-BUSY from other side will convert
this to Y-side protocol and the
ctc_mpc_alloc_channel flow will begin.
MPCG_STATE_XID0IOWAIX XID2(0) negotiations are in progress.
At least 1, but not all, XID2(0)'s
have been received from partner.
MPCG_STATE_XID7INITI XID2(0) complete
No XID2(7)'s have yet been received.
XID2(7) negotiations pending.
MPCG_STATE_XID7INITZ XID2(7) negotiations in progress.
At least 1, but not all, XID2(7)'s
have been received from partner.
MPCG_STATE_XID7INITF XID2(7) negotiations complete.
Transitioning to READY.
MPCG_STATE_READY Ready for Data Transfer.
*/
enum mpcg_events {
MPCG_EVENT_INOP,
MPCG_EVENT_DISCONC,
MPCG_EVENT_XID0DO,
MPCG_EVENT_XID2,
MPCG_EVENT_XID2DONE,
MPCG_EVENT_XID7DONE,
MPCG_EVENT_TIMER,
MPCG_EVENT_DOIO,
MPCG_NR_EVENTS,
};
enum mpcg_states {
MPCG_STATE_RESET,
MPCG_STATE_INOP,
MPCG_STATE_XID2INITW,
MPCG_STATE_XID2INITX,
MPCG_STATE_XID7INITW,
MPCG_STATE_XID7INITX,
MPCG_STATE_XID0IOWAIT,
MPCG_STATE_XID0IOWAIX,
MPCG_STATE_XID7INITI,
MPCG_STATE_XID7INITZ,
MPCG_STATE_XID7INITF,
MPCG_STATE_FLOWC,
MPCG_STATE_READY,
MPCG_NR_STATES,
};
#endif
/* --- This is the END my friend --- */

1772
drivers/s390/net/ctcm_main.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,287 @@
/*
* drivers/s390/net/ctcm_main.h
*
* Copyright IBM Corp. 2001, 2007
* Authors: Fritz Elfert (felfert@millenux.com)
* Peter Tiedemann (ptiedem@de.ibm.com)
*/
#ifndef _CTCM_MAIN_H_
#define _CTCM_MAIN_H_
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include "fsm.h"
#include "cu3088.h"
#include "ctcm_dbug.h"
#include "ctcm_mpc.h"
#define CTC_DRIVER_NAME "ctcm"
#define CTC_DEVICE_NAME "ctc"
#define CTC_DEVICE_GENE "ctc%d"
#define MPC_DEVICE_NAME "mpc"
#define MPC_DEVICE_GENE "mpc%d"
#define CHANNEL_FLAGS_READ 0
#define CHANNEL_FLAGS_WRITE 1
#define CHANNEL_FLAGS_INUSE 2
#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
#define CHANNEL_FLAGS_FAILED 8
#define CHANNEL_FLAGS_WAITIRQ 16
#define CHANNEL_FLAGS_RWMASK 1
#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
#define LOG_FLAG_ILLEGALPKT 1
#define LOG_FLAG_ILLEGALSIZE 2
#define LOG_FLAG_OVERRUN 4
#define LOG_FLAG_NOMEM 8
#define ctcm_pr_debug(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
#define ctcm_pr_info(fmt, arg...) printk(KERN_INFO fmt, ##arg)
#define ctcm_pr_notice(fmt, arg...) printk(KERN_NOTICE fmt, ##arg)
#define ctcm_pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
#define ctcm_pr_emerg(fmt, arg...) printk(KERN_EMERG fmt, ##arg)
#define ctcm_pr_err(fmt, arg...) printk(KERN_ERR fmt, ##arg)
#define ctcm_pr_crit(fmt, arg...) printk(KERN_CRIT fmt, ##arg)
/*
* CCW commands, used in this driver.
*/
#define CCW_CMD_WRITE 0x01
#define CCW_CMD_READ 0x02
#define CCW_CMD_NOOP 0x03
#define CCW_CMD_TIC 0x08
#define CCW_CMD_SENSE_CMD 0x14
#define CCW_CMD_WRITE_CTL 0x17
#define CCW_CMD_SET_EXTENDED 0xc3
#define CCW_CMD_PREPARE 0xe3
#define CTCM_PROTO_S390 0
#define CTCM_PROTO_LINUX 1
#define CTCM_PROTO_LINUX_TTY 2
#define CTCM_PROTO_OS390 3
#define CTCM_PROTO_MPC 4
#define CTCM_PROTO_MAX 4
#define CTCM_BUFSIZE_LIMIT 65535
#define CTCM_BUFSIZE_DEFAULT 32768
#define MPC_BUFSIZE_DEFAULT CTCM_BUFSIZE_LIMIT
#define CTCM_TIME_1_SEC 1000
#define CTCM_TIME_5_SEC 5000
#define CTCM_TIME_10_SEC 10000
#define CTCM_INITIAL_BLOCKLEN 2
#define READ 0
#define WRITE 1
#define CTCM_ID_SIZE BUS_ID_SIZE+3
struct ctcm_profile {
unsigned long maxmulti;
unsigned long maxcqueue;
unsigned long doios_single;
unsigned long doios_multi;
unsigned long txlen;
unsigned long tx_time;
struct timespec send_stamp;
};
/*
* Definition of one channel
*/
struct channel {
struct channel *next;
char id[CTCM_ID_SIZE];
struct ccw_device *cdev;
/*
* Type of this channel.
* CTC/A or Escon for valid channels.
*/
enum channel_types type;
/*
* Misc. flags. See CHANNEL_FLAGS_... below
*/
__u32 flags;
__u16 protocol; /* protocol of this channel (4 = MPC) */
/*
* I/O and irq related stuff
*/
struct ccw1 *ccw;
struct irb *irb;
/*
* RX/TX buffer size
*/
int max_bufsize;
struct sk_buff *trans_skb; /* transmit/receive buffer */
struct sk_buff_head io_queue; /* universal I/O queue */
struct tasklet_struct ch_tasklet; /* MPC ONLY */
/*
* TX queue for collecting skb's during busy.
*/
struct sk_buff_head collect_queue;
/*
* Amount of data in collect_queue.
*/
int collect_len;
/*
* spinlock for collect_queue and collect_len
*/
spinlock_t collect_lock;
/*
* Timer for detecting unresposive
* I/O operations.
*/
fsm_timer timer;
/* MPC ONLY section begin */
__u32 th_seq_num; /* SNA TH seq number */
__u8 th_seg;
__u32 pdu_seq;
struct sk_buff *xid_skb;
char *xid_skb_data;
struct th_header *xid_th;
struct xid2 *xid;
char *xid_id;
struct th_header *rcvd_xid_th;
struct xid2 *rcvd_xid;
char *rcvd_xid_id;
__u8 in_mpcgroup;
fsm_timer sweep_timer;
struct sk_buff_head sweep_queue;
struct th_header *discontact_th;
struct tasklet_struct ch_disc_tasklet;
/* MPC ONLY section end */
int retry; /* retry counter for misc. operations */
fsm_instance *fsm; /* finite state machine of this channel */
struct net_device *netdev; /* corresponding net_device */
struct ctcm_profile prof;
unsigned char *trans_skb_data;
__u16 logflags;
};
struct ctcm_priv {
struct net_device_stats stats;
unsigned long tbusy;
/* The MPC group struct of this interface */
struct mpc_group *mpcg; /* MPC only */
struct xid2 *xid; /* MPC only */
/* The finite state machine of this interface */
fsm_instance *fsm;
/* The protocol of this device */
__u16 protocol;
/* Timer for restarting after I/O Errors */
fsm_timer restart_timer;
int buffer_size; /* ctc only */
struct channel *channel[2];
};
int ctcm_open(struct net_device *dev);
int ctcm_close(struct net_device *dev);
/*
* prototypes for non-static sysfs functions
*/
int ctcm_add_attributes(struct device *dev);
void ctcm_remove_attributes(struct device *dev);
int ctcm_add_files(struct device *dev);
void ctcm_remove_files(struct device *dev);
/*
* Compatibility macros for busy handling
* of network devices.
*/
static inline void ctcm_clear_busy_do(struct net_device *dev)
{
clear_bit(0, &(((struct ctcm_priv *)dev->priv)->tbusy));
netif_wake_queue(dev);
}
static inline void ctcm_clear_busy(struct net_device *dev)
{
struct mpc_group *grp;
grp = ((struct ctcm_priv *)dev->priv)->mpcg;
if (!(grp && grp->in_sweep))
ctcm_clear_busy_do(dev);
}
static inline int ctcm_test_and_set_busy(struct net_device *dev)
{
netif_stop_queue(dev);
return test_and_set_bit(0, &(((struct ctcm_priv *)dev->priv)->tbusy));
}
extern int loglevel;
extern struct channel *channels;
void ctcm_unpack_skb(struct channel *ch, struct sk_buff *pskb);
/*
* Functions related to setup and device detection.
*/
static inline int ctcm_less_than(char *id1, char *id2)
{
unsigned long dev1, dev2;
id1 = id1 + 5;
id2 = id2 + 5;
dev1 = simple_strtoul(id1, &id1, 16);
dev2 = simple_strtoul(id2, &id2, 16);
return (dev1 < dev2);
}
int ctcm_ch_alloc_buffer(struct channel *ch);
static inline int ctcm_checkalloc_buffer(struct channel *ch)
{
if (ch->trans_skb == NULL)
return ctcm_ch_alloc_buffer(ch);
if (ch->flags & CHANNEL_FLAGS_BUFSIZE_CHANGED) {
dev_kfree_skb(ch->trans_skb);
return ctcm_ch_alloc_buffer(ch);
}
return 0;
}
struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv);
/* test if protocol attribute (of struct ctcm_priv or struct channel)
* has MPC protocol setting. Type is not checked
*/
#define IS_MPC(p) ((p)->protocol == CTCM_PROTO_MPC)
/* test if struct ctcm_priv of struct net_device has MPC protocol setting */
#define IS_MPCDEV(d) IS_MPC((struct ctcm_priv *)d->priv)
static inline gfp_t gfp_type(void)
{
return in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
}
/*
* Definition of our link level header.
*/
struct ll_header {
__u16 length;
__u16 type;
__u16 unused;
};
#define LL_HEADER_LENGTH (sizeof(struct ll_header))
#endif

2472
drivers/s390/net/ctcm_mpc.c Normal file

File diff suppressed because it is too large Load Diff

239
drivers/s390/net/ctcm_mpc.h Normal file
View File

@ -0,0 +1,239 @@
/*
* drivers/s390/net/ctcm_mpc.h
*
* Copyright IBM Corp. 2007
* Authors: Peter Tiedemann (ptiedem@de.ibm.com)
*
* MPC additions:
* Belinda Thompson (belindat@us.ibm.com)
* Andy Richter (richtera@us.ibm.com)
*/
#ifndef _CTC_MPC_H_
#define _CTC_MPC_H_
#include <linux/skbuff.h>
#include "fsm.h"
/*
* MPC external interface
* Note that ctc_mpc_xyz are called with a lock on ................
*/
/* port_number is the mpc device 0, 1, 2 etc mpc2 is port_number 2 */
/* passive open Just wait for XID2 exchange */
extern int ctc_mpc_alloc_channel(int port,
void (*callback)(int port_num, int max_write_size));
/* active open Alloc then send XID2 */
extern void ctc_mpc_establish_connectivity(int port,
void (*callback)(int port_num, int rc, int max_write_size));
extern void ctc_mpc_dealloc_ch(int port);
extern void ctc_mpc_flow_control(int port, int flowc);
/*
* other MPC Group prototypes and structures
*/
#define ETH_P_SNA_DIX 0x80D5
/*
* Declaration of an XID2
*
*/
#define ALLZEROS 0x0000000000000000
#define XID_FM2 0x20
#define XID2_0 0x00
#define XID2_7 0x07
#define XID2_WRITE_SIDE 0x04
#define XID2_READ_SIDE 0x05
struct xid2 {
__u8 xid2_type_id;
__u8 xid2_len;
__u32 xid2_adj_id;
__u8 xid2_rlen;
__u8 xid2_resv1;
__u8 xid2_flag1;
__u8 xid2_fmtt;
__u8 xid2_flag4;
__u16 xid2_resv2;
__u8 xid2_tgnum;
__u32 xid2_sender_id;
__u8 xid2_flag2;
__u8 xid2_option;
char xid2_resv3[8];
__u16 xid2_resv4;
__u8 xid2_dlc_type;
__u16 xid2_resv5;
__u8 xid2_mpc_flag;
__u8 xid2_resv6;
__u16 xid2_buf_len;
char xid2_buffer[255 - (13 * sizeof(__u8) +
2 * sizeof(__u32) +
4 * sizeof(__u16) +
8 * sizeof(char))];
} __attribute__ ((packed));
#define XID2_LENGTH (sizeof(struct xid2))
struct th_header {
__u8 th_seg;
__u8 th_ch_flag;
#define TH_HAS_PDU 0xf0
#define TH_IS_XID 0x01
#define TH_SWEEP_REQ 0xfe
#define TH_SWEEP_RESP 0xff
__u8 th_blk_flag;
#define TH_DATA_IS_XID 0x80
#define TH_RETRY 0x40
#define TH_DISCONTACT 0xc0
#define TH_SEG_BLK 0x20
#define TH_LAST_SEG 0x10
#define TH_PDU_PART 0x08
__u8 th_is_xid; /* is 0x01 if this is XID */
__u32 th_seq_num;
} __attribute__ ((packed));
struct th_addon {
__u32 th_last_seq;
__u32 th_resvd;
} __attribute__ ((packed));
struct th_sweep {
struct th_header th;
struct th_addon sw;
} __attribute__ ((packed));
#define TH_HEADER_LENGTH (sizeof(struct th_header))
#define TH_SWEEP_LENGTH (sizeof(struct th_sweep))
#define PDU_LAST 0x80
#define PDU_CNTL 0x40
#define PDU_FIRST 0x20
struct pdu {
__u32 pdu_offset;
__u8 pdu_flag;
__u8 pdu_proto; /* 0x01 is APPN SNA */
__u16 pdu_seq;
} __attribute__ ((packed));
#define PDU_HEADER_LENGTH (sizeof(struct pdu))
struct qllc {
__u8 qllc_address;
#define QLLC_REQ 0xFF
#define QLLC_RESP 0x00
__u8 qllc_commands;
#define QLLC_DISCONNECT 0x53
#define QLLC_UNSEQACK 0x73
#define QLLC_SETMODE 0x93
#define QLLC_EXCHID 0xBF
} __attribute__ ((packed));
/*
* Definition of one MPC group
*/
#define MAX_MPCGCHAN 10
#define MPC_XID_TIMEOUT_VALUE 10000
#define MPC_CHANNEL_ADD 0
#define MPC_CHANNEL_REMOVE 1
#define MPC_CHANNEL_ATTN 2
#define XSIDE 1
#define YSIDE 0
struct mpcg_info {
struct sk_buff *skb;
struct channel *ch;
struct xid2 *xid;
struct th_sweep *sweep;
struct th_header *th;
};
struct mpc_group {
struct tasklet_struct mpc_tasklet;
struct tasklet_struct mpc_tasklet2;
int changed_side;
int saved_state;
int channels_terminating;
int out_of_sequence;
int flow_off_called;
int port_num;
int port_persist;
int alloc_called;
__u32 xid2_adj_id;
__u8 xid2_tgnum;
__u32 xid2_sender_id;
int num_channel_paths;
int active_channels[2];
__u16 group_max_buflen;
int outstanding_xid2;
int outstanding_xid7;
int outstanding_xid7_p2;
int sweep_req_pend_num;
int sweep_rsp_pend_num;
struct sk_buff *xid_skb;
char *xid_skb_data;
struct th_header *xid_th;
struct xid2 *xid;
char *xid_id;
struct th_header *rcvd_xid_th;
struct sk_buff *rcvd_xid_skb;
char *rcvd_xid_data;
__u8 in_sweep;
__u8 roll;
struct xid2 *saved_xid2;
void (*allochanfunc)(int, int);
int allocchan_callback_retries;
void (*estconnfunc)(int, int, int);
int estconn_callback_retries;
int estconn_called;
int xidnogood;
int send_qllc_disc;
fsm_timer timer;
fsm_instance *fsm; /* group xid fsm */
};
#ifdef DEBUGDATA
void ctcmpc_dumpit(char *buf, int len);
#else
static inline void ctcmpc_dumpit(char *buf, int len)
{
}
#endif
#ifdef DEBUGDATA
/*
* Dump header and first 16 bytes of an sk_buff for debugging purposes.
*
* skb The struct sk_buff to dump.
* offset Offset relative to skb-data, where to start the dump.
*/
void ctcmpc_dump_skb(struct sk_buff *skb, int offset);
#else
static inline void ctcmpc_dump_skb(struct sk_buff *skb, int offset)
{}
#endif
static inline void ctcmpc_dump32(char *buf, int len)
{
if (len < 32)
ctcmpc_dumpit(buf, len);
else
ctcmpc_dumpit(buf, 32);
}
int ctcmpc_open(struct net_device *);
void ctcm_ccw_check_rc(struct channel *, int, char *);
void mpc_group_ready(unsigned long adev);
int mpc_channel_action(struct channel *ch, int direction, int action);
void mpc_action_send_discontact(unsigned long thischan);
void mpc_action_discontact(fsm_instance *fi, int event, void *arg);
void ctcmpc_bh(unsigned long thischan);
#endif
/* --- This is the END my friend --- */

View File

@ -0,0 +1,210 @@
/*
* drivers/s390/net/ctcm_sysfs.c
*
* Copyright IBM Corp. 2007, 2007
* Authors: Peter Tiedemann (ptiedem@de.ibm.com)
*
*/
#undef DEBUG
#undef DEBUGDATA
#undef DEBUGCCW
#include <linux/sysfs.h>
#include "ctcm_main.h"
/*
* sysfs attributes
*/
static ssize_t ctcm_buffer_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ctcm_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
return sprintf(buf, "%d\n", priv->buffer_size);
}
static ssize_t ctcm_buffer_write(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct net_device *ndev;
int bs1;
struct ctcm_priv *priv = dev_get_drvdata(dev);
if (!(priv && priv->channel[READ] &&
(ndev = priv->channel[READ]->netdev))) {
CTCM_DBF_TEXT(SETUP, CTC_DBF_ERROR, "bfnondev");
return -ENODEV;
}
sscanf(buf, "%u", &bs1);
if (bs1 > CTCM_BUFSIZE_LIMIT)
goto einval;
if (bs1 < (576 + LL_HEADER_LENGTH + 2))
goto einval;
priv->buffer_size = bs1; /* just to overwrite the default */
if ((ndev->flags & IFF_RUNNING) &&
(bs1 < (ndev->mtu + LL_HEADER_LENGTH + 2)))
goto einval;
priv->channel[READ]->max_bufsize = bs1;
priv->channel[WRITE]->max_bufsize = bs1;
if (!(ndev->flags & IFF_RUNNING))
ndev->mtu = bs1 - LL_HEADER_LENGTH - 2;
priv->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
priv->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
CTCM_DBF_DEV(SETUP, ndev, buf);
return count;
einval:
CTCM_DBF_DEV(SETUP, ndev, "buff_err");
return -EINVAL;
}
static void ctcm_print_statistics(struct ctcm_priv *priv)
{
char *sbuf;
char *p;
if (!priv)
return;
sbuf = kmalloc(2048, GFP_KERNEL);
if (sbuf == NULL)
return;
p = sbuf;
p += sprintf(p, " Device FSM state: %s\n",
fsm_getstate_str(priv->fsm));
p += sprintf(p, " RX channel FSM state: %s\n",
fsm_getstate_str(priv->channel[READ]->fsm));
p += sprintf(p, " TX channel FSM state: %s\n",
fsm_getstate_str(priv->channel[WRITE]->fsm));
p += sprintf(p, " Max. TX buffer used: %ld\n",
priv->channel[WRITE]->prof.maxmulti);
p += sprintf(p, " Max. chained SKBs: %ld\n",
priv->channel[WRITE]->prof.maxcqueue);
p += sprintf(p, " TX single write ops: %ld\n",
priv->channel[WRITE]->prof.doios_single);
p += sprintf(p, " TX multi write ops: %ld\n",
priv->channel[WRITE]->prof.doios_multi);
p += sprintf(p, " Netto bytes written: %ld\n",
priv->channel[WRITE]->prof.txlen);
p += sprintf(p, " Max. TX IO-time: %ld\n",
priv->channel[WRITE]->prof.tx_time);
printk(KERN_INFO "Statistics for %s:\n%s",
priv->channel[WRITE]->netdev->name, sbuf);
kfree(sbuf);
return;
}
static ssize_t stats_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ctcm_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
ctcm_print_statistics(priv);
return sprintf(buf, "0\n");
}
static ssize_t stats_write(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct ctcm_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
/* Reset statistics */
memset(&priv->channel[WRITE]->prof, 0,
sizeof(priv->channel[WRITE]->prof));
return count;
}
static ssize_t ctcm_proto_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ctcm_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
return sprintf(buf, "%d\n", priv->protocol);
}
static ssize_t ctcm_proto_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int value;
struct ctcm_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
sscanf(buf, "%u", &value);
if (!((value == CTCM_PROTO_S390) ||
(value == CTCM_PROTO_LINUX) ||
(value == CTCM_PROTO_MPC) ||
(value == CTCM_PROTO_OS390)))
return -EINVAL;
priv->protocol = value;
CTCM_DBF_DEV(SETUP, dev, buf);
return count;
}
static ssize_t ctcm_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ccwgroup_device *cgdev;
cgdev = to_ccwgroupdev(dev);
if (!cgdev)
return -ENODEV;
return sprintf(buf, "%s\n",
cu3088_type[cgdev->cdev[0]->id.driver_info]);
}
static DEVICE_ATTR(buffer, 0644, ctcm_buffer_show, ctcm_buffer_write);
static DEVICE_ATTR(protocol, 0644, ctcm_proto_show, ctcm_proto_store);
static DEVICE_ATTR(type, 0444, ctcm_type_show, NULL);
static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
static struct attribute *ctcm_attr[] = {
&dev_attr_protocol.attr,
&dev_attr_type.attr,
&dev_attr_buffer.attr,
NULL,
};
static struct attribute_group ctcm_attr_group = {
.attrs = ctcm_attr,
};
int ctcm_add_attributes(struct device *dev)
{
int rc;
rc = device_create_file(dev, &dev_attr_stats);
return rc;
}
void ctcm_remove_attributes(struct device *dev)
{
device_remove_file(dev, &dev_attr_stats);
}
int ctcm_add_files(struct device *dev)
{
return sysfs_create_group(&dev->kobj, &ctcm_attr_group);
}
void ctcm_remove_files(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &ctcm_attr_group);
}