📄 ctc.c
字号:
/* * drivers/s390/net/ctc.c * CTC / ESCON network driver * * S390 version * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Dieter Wellerdiek (wel@de.ibm.com) * * 2.3 Updates Martin Schwidefsky (schwidefsky@de.ibm.com) * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) * * * Description of the Kernel Parameter * Normally the CTC driver selects the channels in order (automatic channel * selection). If your installation needs to use the channels in a different * order or doesn't want to have automatic channel selection on, you can do * this with the "ctc= kernel keyword". * * ctc=0,0xrrrr,0xwwww,ddddd * * Where: * * "rrrr" is the read channel address * "wwww" is the write channel address * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 * to escon7 for ESCON channels). * * To switch the automatic channel selection off use the ctc= keyword with * parameter "noauto". This may be necessary if you 3271 devices or other devices * which use the ctc device type and model, but operate with a different protocol. * * ctc=noauto * * Change History * 0.50 Initial release shipped * 0.51 Bug fixes * - CTC / ESCON network device can now handle up to 64 channels * - 3088-61 info message supperssed - CISCO 7206 - CLAW - ESCON * - 3088-62 info message suppressed - OSA/D * - channel: def ffffffed ... error message suppressed * - CTC / ESCON device was not recoverable after a lost connection with * IFCONFIG dev DOWN and IFCONFIG dev UP * - Possibility to switch the automatic selection off * - Minor bug fixes */#include <linux/version.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/timer.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/string.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ip.h>#include <linux/if_arp.h>#include <linux/tcp.h>#include <linux/skbuff.h>#include <asm/io.h>#include <asm/bitops.h> #include <asm/irq.h>//#define DEBUG /* Redefine message level, so that all messages occur on 3215 console in DEBUG mode */#ifdef DEBUG #undef KERN_INFO #undef KERN_WARNING #undef KERN_DEBUG #define KERN_INFO KERN_EMERG #define KERN_WARNING KERN_EMERG #define KERN_DEBUG KERN_EMERG#endif //#undef DEBUG#define CCW_CMD_WRITE 0x01#define CCW_CMD_READ 0x02#define CCW_CMD_SET_EXTENDED 0xc3#define CCW_CMD_PREPARE 0xe3#define MAX_CHANNEL_DEVICES 64 #define MAX_ADAPTERS 8#define CTC_DEFAULT_MTU_SIZE 1500#define READ 0#define WRITE 1#define CTC 0#define ESCON 1#define CHANNEL_MEDIA 2#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */#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 */ /* state machine codes used in ctc_irq_handler */#define CTC_STOP 0#define CTC_START_HALT_IO 1#define CTC_START_SET_X_MODE 2#define CTC_START_SELECT 4 #define CTC_START_READ_TEST 32#define CTC_START_READ 33#define CTC_START_WRITE_TEST 64#define CTC_START_WRITE 65typedef enum { channel_type_none, /* Device is not a channel */ channel_type_undefined, /* Device is a channel but we don't know anything about it */ channel_type_ctca, /* Device is a CTC/A and we can deal with it */ channel_type_escon, /* Device is a ESCON channel and we can deal with it */ channel_type_unsupported /* Device is a unsupported model */} channel_type_t; /* * Structures needed in the initial phase * */ static int channel_tab_initialized = 0; /* channel[] structure initialized */struct devicelist { unsigned int devno; __u8 flag;#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */}; static struct { struct devicelist list[MAX_CHANNEL_DEVICES]; int count; int left;} channel[CHANNEL_MEDIA];static int ctc_no_auto = 0;struct adapterlist{ unsigned int devno[2]; __u16 protocol;};static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON *//* * Structure used after the initial phase * */ struct buffer { struct buffer *next; int packets; struct block *block;};#if LINUX_VERSION_CODE>=0x020300typedef struct net_device net_device;#elsetypedef struct device net_device;typedef struct wait_queue* wait_queue_head_t;#define DECLARE_WAITQUEUE(waitqname,waitqtask) struct wait_queue waitqname = {waitqtask, NULL }#define init_waitqueue_head(nothing)#endifstruct channel { unsigned int devno; int irq; unsigned long IO_active; ccw1_t ccw[3]; __u32 state; int buffer_count; struct buffer *free_anchor; struct buffer *proc_anchor; devstat_t *devstat; net_device *dev; /* backward pointer to the network device */ wait_queue_head_t wait; struct tq_struct tq; struct timer_list timer; unsigned long flag_a; /* atomic flags */#define CTC_BH_ACTIVE 0 __u8 last_dstat; __u8 flag;#define CTC_WRITE 0x01 /* - Set if this is a write channel */#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ };struct ctc_priv { struct net_device_stats stats;#if LINUX_VERSION_CODE>=0x02032D int tbusy;#endif struct channel channel[2]; __u16 protocol;}; /* * This structure works as shuttle between two systems * - A block can contain one or more packets */#define PACKET_HEADER_LENGTH 6struct packet { __u16 length; __u16 type; __u16 unused; __u8 data;}; #define BLOCK_HEADER_LENGTH 2struct block { __u16 length; struct packet data;};#if LINUX_VERSION_CODE>=0x02032D#define ctc_protect_busy(dev) \s390irq_spin_lock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq)#define ctc_unprotect_busy(dev) \s390irq_spin_unlock(((struct ctc_priv *)dev->priv)->channel[WRITE].irq)#define ctc_protect_busy_irqsave(dev,flags) \s390irq_spin_lock_irqsave(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags)#define ctc_unprotect_busy_irqrestore(dev,flags) \s390irq_spin_unlock_irqrestore(((struct ctc_priv *)dev->priv)->channel[WRITE].irq,flags)static __inline__ void ctc_set_busy(net_device *dev){ ((struct ctc_priv *)dev->priv)->tbusy=1; netif_stop_queue(dev);}static __inline__ void ctc_clear_busy(net_device *dev){ ((struct ctc_priv *)dev->priv)->tbusy=0; netif_start_queue(dev);}static __inline__ int ctc_check_busy(net_device *dev){ eieio(); return(((struct ctc_priv *)dev->priv)->tbusy);}static __inline__ void ctc_setbit_busy(int nr,net_device *dev){ set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); netif_stop_queue(dev); }static __inline__ void ctc_clearbit_busy(int nr,net_device *dev){ clear_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); if(((struct ctc_priv *)dev->priv)->tbusy==0) netif_start_queue(dev);}static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev){ netif_stop_queue(dev); return(test_and_set_bit(nr,&((struct ctc_priv *)dev->priv)->tbusy));}#else#define ctc_protect_busy(dev)#define ctc_unprotect_busy(dev)#define ctc_protect_busy_irqsave(dev,flags)#define ctc_unprotect_busy_irqrestore(dev,flags)static __inline__ void ctc_set_busy(net_device *dev){ dev->tbusy=1; eieio();}static __inline__ void ctc_clear_busy(net_device *dev){ dev->tbusy=0; eieio();}static __inline__ int ctc_check_busy(net_device *dev){ eieio(); return(dev->tbusy);}static __inline__ void ctc_setbit_busy(int nr,net_device *dev){ set_bit(nr,(void *)&dev->tbusy);}static __inline__ void ctc_clearbit_busy(int nr,net_device *dev){ clear_bit(nr,(void *)&dev->tbusy);}static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev){ return(test_and_set_bit(nr,(void *)&dev->tbusy));}#endif/* Interrupt handler */static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs);static void ctc_irq_bh(struct channel *ctc); static void ctc_read_retry (struct channel *ctc);static void ctc_write_retry (struct channel *ctc);/* Functions for the DEV methods */int ctc_probe(net_device *dev); static int ctc_open(net_device *dev); static void ctc_timer (struct channel *ctc);static int ctc_release(net_device *dev);static int ctc_tx(struct sk_buff *skb, net_device *dev);static int ctc_change_mtu(net_device *dev, int new_mtu);struct net_device_stats* ctc_stats(net_device *dev); /* * Channel Routines * */ static void channel_init(void);static void channel_scan(void);static int channel_get(int media, int devno);static int channel_get_next(int media); static int channel_free(int media, int devno);static channel_type_t channel_check_for_type (senseid_t *id);static void channel_sort(struct devicelist list[], int n);/* * initialize the channel[].list */ static void channel_init(void) { int m;#ifdef DEBUG int c;#endif if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){ channel_scan(); for (m = 0; m < CHANNEL_MEDIA; m++) { channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); channel[m].left = channel[m].count; } if (channel[CTC].count == 0 && channel[ESCON].count == 0) printk(KERN_INFO "channel: no Channel devices recognized\n"); else printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n", channel[CTC].count, channel[ESCON].count); #ifdef DEBUG for (m = 0; m < CHANNEL_MEDIA; m++) { for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", m, c, channel[m].list[c].devno); } }#endif }}/** scan for all channels and put the device numbers into the channel[].list */ static void channel_scan(void){ int m; int c; int irq;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -