patch-2.2.18 linux/drivers/s390/net/ctc.c
Next file: linux/drivers/s390/net/iucv.c
Previous file: linux/drivers/s390/net/Makefile
Back to the patch index
Back to the overall index
- Lines: 3049
- Date:
Sat Dec 9 20:56:00 2000
- Orig file:
v2.2.17/drivers/s390/net/ctc.c
- Orig date:
Sat Sep 9 18:42:40 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
@@ -1,4 +1,6 @@
/*
+ * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $
+ *
* drivers/s390/net/ctc.c
* CTC / ESCON network driver
*
@@ -7,7 +9,11 @@
* 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)
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * Modularization & Bugfixes by Fritz Elfert (fritz.elfert@millenux.de)
+ *
+ * Bugfixes by Jochen Röhrig (roehrig@de.ibm.com)
*
*
* Description of the Kernel Parameter
@@ -16,50 +22,142 @@
* 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
+ * 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).
+ * "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
+ * ctc=noauto
+ *
+ * $Log: ctc.c,v $
+ * Revision 1.25.2.5 2000/10/11 15:08:59 bird
+ * ctc_tx(): Quick fix of possible underflow when calculating free block space
+ *
+ * Revision 1.25.2.4 2000/09/25 16:40:56 bird
+ * Some more debug information
+ *
+ * Revision 1.25.2.3 2000/09/20 13:28:19 bird
+ * - ctc_open(): fixed bug
+ * - ctc_release(): added timer for terminating in case of halt_io()-hang
+ *
+ * Revision 1.25.2.2 2000/09/20 09:48:27 bird
+ * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in
+ * instead of direct waiting on a wait queue
+ * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check():
+ * print more debug information
+ *
+ * Revision 1.25.2.1 2000/09/19 09:09:56 bird
+ * Merged in changes from 1.25 to 1.26
+ *
+ * Revision 1.25 2000/09/08 09:22:11 bird
+ * Proper cleanup and bugfixes in ctc_probe()
+ *
+ * Revision 1.24 2000/08/30 15:14:38 bird
+ * Some bugfixes and simplifications in ctc_probe()
+ *
+ * Revision 1.23 2000/08/28 16:50:35 bird
+ * - Suppress warning if discarding initial handshake block
+ * - Removed strstr() (now exported in arch/s390/kernel/s390_ksyms.c)
+ *
+ * Revision 1.22 2000/08/28 11:33:21 felfert
+ * Remove some dead code in ctc_open().
+ *
+ * Revision 1.21 2000/08/28 09:31:06 bird
+ * init_module(): fixed pointer arithmetic (device name)
+ *
+ * Revision 1.20 2000/08/25 20:11:56 bird
+ * Didn´t build as non-module.
+ *
+ * Revision 1.19 2000/08/25 19:48:46 felfert
+ * Modularized version.
+ *
+ * Revision 1.18 2000/08/25 19:34:29 bird
+ * extract_channel_id():
+ * - check for valid channel id;
+ * return -EINVAL in case of violation
+ *
+ * ctc_setup():
+ * - check for valid channel id;
+ * return without doing anything in case of violation
+ *
+ * ctc_irq_bh():
+ * - check for valid block length and packet length;
+ * discard block in case of invalid values
+ * (solves infinite loop problem that occurs if (for some unknown reason)
+ * the packet length = 0)
+ *
+ * Revision 1.17 2000/08/25 09:22:51 bird
+ * ctc_buffer_alloc():
+ * fixed kmalloc()-bug (allocated buffer of wrong size)
+ *
+ * Revision 1.16 2000/08/24 17:46:19 bird
+ * ctc_write_retry():
+ * - removed (presumably useless) loop for cleaning up the proc_anchor list.
+ * - inserted warning if proc_anchor (unexpectedly) != NULL
+ *
+ * Revision 1.15 2000/08/24 15:25:04 bird
+ * ctc_read_retry():
+ * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set
+ * - removed some useless debug-messages
+ * ctc_write_retry():
+ * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set
+ *
+ * Revision 1.14 2000/08/24 09:34:47 felfert
+ * Fixed bug in ctc_release:
+ * - ctc_unprotect_busy_irqrestore was called with wrong parameter.
+ *
*
- * Change History
+ * Old 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 suppressed - 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
+ * - CTC / ESCON network device can now handle up to 64 channels
+ * - 3088-61 info message suppressed - 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
* 0.52 Bug fixes
- * - Subchannel check message enhanced
- * - Read / Write retry routine check for CTC_STOP added
+ * - Subchannel check message enhanced
+ * - Read / Write retry routine check for CTC_STOP added
* 0.53 Enhancement
- * - Connect time changed from 150 to 300 seconds
- * This gives more a better chance to connect during IPL
+ * - Connect time changed from 150 to 300 seconds
+ * This gives more a better chance to connect during IPL
* 0.54 Bug fixes
- * - Out of memory message enhanced
- * - Zero buffer problem in ctc_irq_hb solved
- * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
- * which could end in a out of memory situation.
+ * - Out of memory message enhanced
+ * - Zero buffer problem in ctc_irq_hb solved
+ * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
+ * which could end in a out of memory situation.
* 0.55 Bug fixes
- * - Connect problems with systems which IPL later
- * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
- * not available. When systemB comes up it is nearly inpossible to setup a
- * connection.
+ * - Connect problems with systems which IPL later
+ * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
+ * not available. When systemB comes up it is nearly inpossible to setup a
+ * connection.
+ *
+ * 0.56 Bug fixes
+ * - ctc_open(): In case of failure stop read/write-retry timers before
+ * freeing buffers (stops kernel panics due to NULL-pointer
+ * dereferences in ctc_read_retry())
+ * - Added some sanity checks concerning NULL-pointer dereferences
+ * - Added some comments
+ *
+ * 0.57 Bug fixes
+ * - CTC / ESCON network device can now handle up to 256 channels
+ * - ctc_read_retry(): added sanity check: if ctc->free_anchor == NULL
+ * print a warning and simply return
*/
+
#include <linux/version.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
@@ -78,6 +176,7 @@
#include <linux/if_arp.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
+#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/bitops.h>
@@ -85,56 +184,67 @@
#include <asm/irq.h>
+#ifdef MODULE
+MODULE_AUTHOR("(C) 2000 IBM Corp. by Dieter Wellerdiek (wel@de.ibm.com)");
+MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+MODULE_PARM(setup,"s");
+MODULE_PARM_DESC(setup,
+"One or more definitions in the same format like the kernel parameter line for ctc.\n"
+"E.g.: \"ctc=0,0x700,0x701,ctc0 ctc=0,0x702,0x703,ctc1\".\n");
+
+char *setup = NULL;
+#endif
+
//#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
-
-
-#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 */
+#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
+
+
+#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 256
+#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 65
+#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 65
typedef 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_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;
@@ -144,30 +254,39 @@
*
*/
-static int channel_tab_initialized = 0; /* channel[] structure initialized */
+static long 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 */
+ 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;
+ struct devicelist list[MAX_CHANNEL_DEVICES];
+ int count;
+ int left;
} channel[CHANNEL_MEDIA];
static int ctc_no_auto = 0;
+#if LINUX_VERSION_CODE>=0x020300
+typedef struct net_device net_device;
+#else
+typedef struct device net_device;
+typedef struct wait_queue* wait_queue_head_t;
+#define init_waitqueue_head(nothing)
+#endif
+
struct adapterlist{
- unsigned int devno[2];
- __u16 protocol;
+ unsigned int devno[2];
+ __u16 protocol;
+ net_device *netdev;
};
-static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */
+static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */
/*
@@ -176,51 +295,43 @@
*/
struct buffer {
- struct buffer *next;
- int packets;
- struct block *block;
+ struct buffer *next;
+ int packets;
+ struct block *block;
};
-#if LINUX_VERSION_CODE>=0x020300
-typedef struct net_device net_device;
-#else
-typedef 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)
-#endif
-
-
struct 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 */
+ 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 tq_struct tq;
+ int initial_block_received; /* only used for read channel */
+ 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_WAKEUP 0x02 /* - Set if this channel should wake up from waiting for an event */
+#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */
};
-struct ctc_priv {
- struct net_device_stats stats;
+struct ctc_priv {
+ struct net_device_stats stats;
#if LINUX_VERSION_CODE>=0x02032D
- int tbusy;
+ unsigned long tbusy;
#endif
- struct channel channel[2];
- __u16 protocol;
+ struct channel channel[2];
+ __u16 protocol;
};
/*
@@ -230,16 +341,16 @@
#define PACKET_HEADER_LENGTH 6
struct packet {
- __u16 length;
- __u16 type;
- __u16 unused;
- __u8 data;
+ __u16 length;
+ __u16 type;
+ __u16 unused;
+ __u8 data;
};
#define BLOCK_HEADER_LENGTH 2
struct block {
- __u16 length;
- struct packet data;
+ __u16 length;
+ struct packet data;
};
#if LINUX_VERSION_CODE>=0x02032D
@@ -275,7 +386,7 @@
static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
{
set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy));
- netif_stop_queue(dev);
+ netif_stop_queue(dev);
}
static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
@@ -318,17 +429,17 @@
static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
{
- set_bit(nr,(void *)&dev->tbusy);
+ set_bit(nr,&dev->tbusy);
}
static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
{
- clear_bit(nr,(void *)&dev->tbusy);
+ clear_bit(nr,&dev->tbusy);
}
static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev)
{
- return(test_and_set_bit(nr,(void *)&dev->tbusy));
+ return(test_and_set_bit(nr,&dev->tbusy));
}
#endif
@@ -338,9 +449,9 @@
/* 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);
+static void ctc_irq_bh(void *data);
+static void ctc_read_retry (unsigned long data);
+static void ctc_write_retry (unsigned long data);
/* Functions for the DEV methods */
@@ -348,7 +459,7 @@
static int ctc_open(net_device *dev);
-static void ctc_timer (struct channel *ctc);
+static void ctc_timer (unsigned long data);
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);
@@ -370,35 +481,55 @@
/*
+ * misc.
+ */
+static void print_banner(void) {
+ static int printed = 0;
+ char vbuf[] = "$Revision: 1.25.2.5 $";
+ char *version = vbuf;
+
+ if (printed)
+ return;
+ if ((version = strchr(version, ':'))) {
+ char *p = strchr(version + 1, '$');
+ if (p)
+ *p = '\0';
+ } else
+ version = " ??? ";
+ printk(KERN_INFO "CTC driver Version%s initialized\n", version);
+ printed = 1;
+}
+
+/*
* initialize the channel[].list
*/
static void channel_init(void)
{
- int m;
+ int m;
#ifdef DEBUG
- int c;
+ 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);
+ if (!test_and_set_bit(0, &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);
- }
- }
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (c = 0; c < channel[m].count; c++){
+ printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n",
+ m, c, channel[m].list[c].devno);
+ }
+ }
#endif
- }
+ }
}
@@ -407,38 +538,37 @@
*/
static void channel_scan(void)
{
- int m;
- int c;
- int irq;
- dev_info_t temp;
-
- for (m = 0; m < CHANNEL_MEDIA; m++) {
- for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
- channel[m].list[c].devno = -ENODEV;
- }
- }
-
- for (irq = 0; irq < NR_IRQS; irq++) {
- /* CTC/A */
- if (channel[CTC].count < MAX_CHANNEL_DEVICES ) {
- if (get_dev_info(irq, &temp) == 0 &&
- channel_check_for_type(&temp.sid_data) == channel_type_ctca) {
- channel[CTC].list[channel[CTC].count].devno = temp.devno;
- channel[CTC].count++;
- }
- }
-
- /* ESCON */
- if (channel[ESCON].count < MAX_CHANNEL_DEVICES ) {
- if (get_dev_info(irq, &temp) == 0 &&
- channel_check_for_type(&temp.sid_data) == channel_type_escon) {
- channel[ESCON].list[channel[ESCON].count].devno = temp.devno;
- channel[ESCON].count++;
-
- }
- }
- }
-}
+ int m;
+ int c;
+ int irq;
+ dev_info_t temp;
+
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
+ channel[m].list[c].devno = -ENODEV;
+ }
+ }
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ if (get_dev_info_by_irq(irq, &temp) == 0) {
+ if ((temp.status == DEVSTAT_NOT_OPER) ||
+ (temp.status == DEVSTAT_DEVICE_OWNED))
+ continue;
+ /* CTC/A */
+ if ((channel[CTC].count < MAX_CHANNEL_DEVICES ) &&
+ (channel_check_for_type(&temp.sid_data) == channel_type_ctca)) {
+ channel[CTC].list[channel[CTC].count].devno = temp.devno;
+ channel[CTC].count++;
+ }
+ /* ESCON */
+ if ((channel[ESCON].count < MAX_CHANNEL_DEVICES ) &&
+ (channel_check_for_type(&temp.sid_data) == channel_type_escon)) {
+ channel[ESCON].list[channel[ESCON].count].devno = temp.devno;
+ channel[ESCON].count++;
+ }
+ }
+ }
+}
/*
@@ -446,17 +576,17 @@
*/
static int channel_free(int media, int devno)
{
- int i;
+ int i;
- for (i = 0; i < channel[media].count; i++) {
- if ((devno == channel[media].list[i].devno) &&
- ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
- channel[media].list[i].flag &= ~CHANNEL_IN_USE;
- return 0;
- }
- }
- printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
- return -ENODEV;
+ for (i = 0; i < channel[media].count; i++) {
+ if ((devno == channel[media].list[i].devno) &&
+ ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
+ channel[media].list[i].flag &= ~CHANNEL_IN_USE;
+ return 0;
+ }
+ }
+ printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+ return -ENODEV;
}
@@ -465,17 +595,17 @@
*/
static int channel_get(int media, int devno)
{
- int i;
+ int i;
- for (i = 0; i < channel[media].count; i++) {
- if ((devno == channel[media].list[i].devno) &&
- ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
- channel[media].list[i].flag |= CHANNEL_IN_USE;
- return channel[media].list[i].devno;
- }
- }
- printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
- return -ENODEV;
+ for (i = 0; i < channel[media].count; i++) {
+ if ((devno == channel[media].list[i].devno) &&
+ ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
+ channel[media].list[i].flag |= CHANNEL_IN_USE;
+ return channel[media].list[i].devno;
+ }
+ }
+ printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+ return -ENODEV;
}
@@ -485,18 +615,18 @@
*/
static int channel_get_next(int media)
{
- int i;
+ int i;
- for (i = 0; i < channel[media].count; i++) {
- if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
+ for (i = 0; i < channel[media].count; i++) {
+ if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
#ifdef DEBUG
- printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
+ printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
#endif
- channel[media].list[i].flag |= CHANNEL_IN_USE;
- return channel[media].list[i].devno;
- }
- }
- return -ENODEV;
+ channel[media].list[i].flag |= CHANNEL_IN_USE;
+ return channel[media].list[i].devno;
+ }
+ }
+ return -ENODEV;
}
@@ -505,7 +635,7 @@
*/
static int channel_left(int media)
{
- return channel[media].left;
+ return channel[media].left;
}
@@ -514,38 +644,38 @@
*/
static channel_type_t channel_check_for_type (senseid_t *id)
{
- channel_type_t type;
+ channel_type_t type;
- switch (id->cu_type) {
- case 0x3088:
+ switch (id->cu_type) {
+ case 0x3088:
- switch (id->cu_model) {
- case 0x08:
- type = channel_type_ctca; /* 3088-08 ==> CTCA */
- break;
-
- case 0x1F:
- type = channel_type_escon; /* 3088-1F ==> ESCON channel */
- break;
+ switch (id->cu_model) {
+ case 0x08:
+ type = channel_type_ctca; /* 3088-08 ==> CTCA */
+ break;
+
+ case 0x1F:
+ type = channel_type_escon; /* 3088-1F ==> ESCON channel */
+ break;
- case 0x01: /* 3088-01 ==> P390 OSA emulation */
- case 0x60: /* 3088-60 ==> OSA/2 adapter */
- case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */
- case 0x62: /* 3088-62 ==> OSA/D device */
- type = channel_type_unsupported;
- break;
-
- default:
- type = channel_type_undefined;
- printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model);
- }
- break;
+ case 0x01: /* 3088-01 ==> P390 OSA emulation */
+ case 0x60: /* 3088-60 ==> OSA/2 adapter */
+ case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */
+ case 0x62: /* 3088-62 ==> OSA/D device */
+ type = channel_type_unsupported;
+ break;
+
+ default:
+ type = channel_type_undefined;
+ printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model);
+ }
+ break;
- default:
- type = channel_type_none;
+ default:
+ type = channel_type_none;
- }
- return type;
+ }
+ return type;
}
@@ -554,22 +684,22 @@
*/
static void channel_sort(struct devicelist list[], int n)
{
- int i;
- int sorted = 0;
- struct devicelist tmp;
-
- while (!sorted) {
- sorted = 1;
-
- for (i = 0; i < n-1; i++) {
- if (list[i].devno > list[i+1].devno) {
- tmp = list[i];
- list[i] = list[i+1];
- list[i+1] = tmp;
- sorted = 0;
- }
- }
- }
+ int i;
+ int sorted = 0;
+ struct devicelist tmp;
+
+ while (!sorted) {
+ sorted = 1;
+
+ for (i = 0; i < n-1; i++) {
+ if (list[i].devno > list[i+1].devno) {
+ tmp = list[i];
+ list[i] = list[i+1];
+ list[i+1] = tmp;
+ sorted = 0;
+ }
+ }
+ }
}
@@ -580,182 +710,216 @@
static int inline extract_channel_id(char *name)
{
- if (name[0] == 'c')
- return (name[3]-'0');
- else
- return (name[5]-'0');
+ int rv = -1;
+
+ if (name[0] == 'c')
+ rv = name[3]-'0';
+ else
+ rv = name[5]-'0';
+
+ if ((rv < 0) || (rv >= MAX_ADAPTERS))
+ rv= -EINVAL;
+
+ return rv;
}
static int inline extract_channel_media(char *name)
{
- if (name[0] == 'c')
- return CTC;
- else
- return ESCON;
+ if (name[0] == 'c')
+ return CTC;
+ else
+ return ESCON;
}
static void ctc_tab_init(void)
-{
- int m;
- int i;
- static int t;
-
- if (t == 0){
- for (m = 0; m < CHANNEL_MEDIA; m++) {
- for (i = 0; i < MAX_ADAPTERS; i++) {
- ctc_adapter[m][i].devno[WRITE] = -ENODEV;
- ctc_adapter[m][i].devno[READ] = -ENODEV;
- }
- }
- t = 1;
- }
+{
+ int m;
+ int i;
+ static int t;
+
+ if (t == 0){
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (i = 0; i < MAX_ADAPTERS; i++) {
+ ctc_adapter[m][i].devno[WRITE] = -ENODEV;
+ ctc_adapter[m][i].devno[READ] = -ENODEV;
+ ctc_adapter[m][i].netdev = NULL;
+ }
+ }
+ t = 1;
+ }
}
static int ctc_buffer_alloc(struct channel *ctc) {
-
- struct buffer *p;
- struct buffer *q;
-
- p = kmalloc(sizeof(p), GFP_KERNEL);
- if (p == NULL)
- return -ENOMEM;
- else {
- p->next = NULL;
- p->packets = 0;
- p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
- if (p->block == NULL) {
- kfree(p);
- return -ENOMEM;
- }
- p->block->length = 0;
- }
+
+ struct buffer *p;
+ struct buffer *q;
+
+ p = kmalloc(sizeof(struct buffer), GFP_KERNEL);
+ if (p == NULL)
+ return -ENOMEM;
+ else {
+ p->next = NULL;
+ p->packets = 0;
+ p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
+ if (p->block == NULL) {
+ kfree(p);
+ return -ENOMEM;
+ }
+ p->block->length = 0;
+ }
- if (ctc->free_anchor == NULL)
- ctc->free_anchor = p;
- else {
- q = ctc->free_anchor;
- while (q->next != NULL)
- q = q->next;
- q->next = p;
- }
- ctc->buffer_count++;
+ if (ctc->free_anchor == NULL)
+ ctc->free_anchor = p;
+ else {
+ q = ctc->free_anchor;
+ while (q->next != NULL)
+ q = q->next;
+ q->next = p;
+ }
+ ctc->buffer_count++;
return 0;
}
static int ctc_buffer_free(struct channel *ctc) {
-
- struct buffer *p;
+
+ struct buffer *p;
-
- if (ctc->free_anchor == NULL)
- return -ENOMEM;
-
- p = ctc->free_anchor;
- ctc->free_anchor = p->next;
- free_pages((__u32)p->block, 4);
- kfree(p);
-
- return 0;
+
+ if (ctc->free_anchor == NULL)
+ return -ENOMEM;
+
+ p = ctc->free_anchor;
+ ctc->free_anchor = p->next;
+ free_pages((unsigned long)p->block, 4);
+ kfree(p);
+
+ return 0;
}
-static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) {
-
- struct buffer *p = NULL;
- struct buffer *q = NULL;
+static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to, net_device *dev) {
+
+ struct buffer *p = NULL;
+ struct buffer *q = NULL;
- if (*from == NULL)
- return -ENOMEM;
-
- p = *from;
- *from = p->next;
- p->next = NULL;
-
- if (*to == NULL)
- *to = p;
- else {
- q = *to;
- while (q->next != NULL)
- q = q->next;
- q->next = p;
-
- }
- return 0;
-}
-
-
+ if (*from == NULL)
+ {
+ printk(KERN_DEBUG
+ "%s: %s(): Trying to swap buffer from empty list - doing nothing\n", dev ? dev->name : "<unknown ctc dev>", __FUNCTION__);
+
+ return -ENOMEM;
+ }
+
+ p = *from;
+ *from = p->next;
+ p->next = NULL;
+
+ if (*to == NULL)
+ *to = p;
+ else {
+ q = *to;
+ while (q->next != NULL)
+ q = q->next;
+ q->next = p;
+
+ }
+ return 0;
+}
+
+#ifdef MODULE
+ static void ctc_setup(char *dev_name,int *ints)
+# define ctc_setup_return return
+#else
+# if LINUX_VERSION_CODE>=0x020300
+ static int __init ctc_setup(char *dev_name)
+# define ctc_setup_return return(1)
+# else
+ __initfunc(void ctc_setup(char *dev_name,int *ints))
+# define ctc_setup_return return
+# endif
+#endif
/*
* ctc_setup function
* this function is called for each ctc= keyword passed into the kernel
*
* valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx
- * where n is the channel protocol always 0
- * 0xnnnn is the cu number read
- * 0xnnnn is the cu number write
- * ctcx can be ctc0 to ctc7 or escon0 to escon7
+ * where n is the channel protocol always 0
+ * 0xnnnn is the cu number read
+ * 0xnnnn is the cu number write
+ * ctcx can be ctc0 to ctc7 or escon0 to escon7
*/
-#if LINUX_VERSION_CODE>=0x020300
-static int __init ctc_setup(char *dev_name)
-#else
-__initfunc(void ctc_setup(char *dev_name,int *ints))
-#endif
+
{
- struct adapterlist tmp;
+ struct adapterlist tmp;
+ int id;
#if LINUX_VERSION_CODE>=0x020300
#define CTC_MAX_PARMS 4
- int ints[CTC_MAX_PARMS+1];
- get_options(dev_name,CTC_MAX_PARMS,ints);
- #define ctc_setup_return return(1)
-#else
- #define ctc_setup_return return
+ int ints[CTC_MAX_PARMS+1];
+ dev_name = get_options(dev_name, CTC_MAX_PARMS, ints);
#endif
- ctc_tab_init();
-
- ctc_no_auto = 1;
-
- if (!strcmp(dev_name,"noauto")) {
- printk(KERN_INFO "ctc: automatic channel selection deactivated\n");
- ctc_setup_return;
- }
-
- tmp.devno[WRITE] = -ENODEV;
- tmp.devno[READ] = -ENODEV;
-
- switch (ints[0]) {
-
- case 3: /* write channel passed */
- tmp.devno[WRITE] = ints[3];
-
- case 2: /* read channel passed */
- tmp.devno[READ] = ints[2];
- if (tmp.devno[WRITE] == -ENODEV)
- tmp.devno[WRITE] = tmp.devno[READ] + 1;
-
- case 1: /* protocol type passed */
- tmp.protocol = ints[1];
- if (tmp.protocol == 0) {
- break;
- } else {
- printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
- ctc_setup_return;
- }
- break;
-
- default:
- printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
- ctc_setup_return;
- }
- ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp;
-#ifdef DEBUG
- printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n",
- dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
-#endif
- ctc_setup_return;
-
+ ctc_tab_init();
+
+ ctc_no_auto = 1;
+
+ if (!dev_name) { /* happens if device name is not specified in
+ parameter line (cf. init/main.c:get_options() */
+ printk(KERN_WARNING
+ "ctc: %s(): Device name not specified\n",
+ __FUNCTION__);
+ ctc_setup_return;
+ }
+
+ if (!strcmp(dev_name,"noauto")) {
+ printk(KERN_INFO "ctc: automatic channel selection deactivated\n");
+ ctc_setup_return;
+ }
+
+ if ((id = extract_channel_id(dev_name)) == -EINVAL)
+ {
+ printk(KERN_WARNING
+ "ctc: %s(): Invalid device name specified: %s\n",
+ __FUNCTION__, dev_name);
+ ctc_setup_return;
+ }
+
+ tmp.devno[WRITE] = -ENODEV;
+ tmp.devno[READ] = -ENODEV;
+
+ switch (ints[0]) {
+
+ case 3: /* write channel passed */
+ tmp.devno[WRITE] = ints[3];
+
+ case 2: /* read channel passed */
+ tmp.devno[READ] = ints[2];
+ if (tmp.devno[WRITE] == -ENODEV)
+ tmp.devno[WRITE] = tmp.devno[READ] + 1;
+
+ case 1: /* protocol type passed */
+ tmp.protocol = ints[1];
+ if (tmp.protocol == 0) {
+ break;
+ } else {
+ printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
+ ctc_setup_return;
+ }
+ break;
+
+ default:
+ printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
+ ctc_setup_return;
+ }
+ ctc_adapter[extract_channel_media(dev_name)][id] = tmp;
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: protocol=%x read=%04x write=%04x\n",
+ dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
+#endif
+ ctc_setup_return;
+
}
#if LINUX_VERSION_CODE>=0x020300
__setup("ctc=", ctc_setup);
@@ -763,102 +927,131 @@
/*
* ctc_probe
- * this function is called for each channel network device,
- * which is defined in the /init/main.c
+ * this function is called for each channel network device,
+ * which is defined in the /init/main.c
*/
int ctc_probe(net_device *dev)
-{
- int rc;
- int c;
- int i;
- int m;
-
- struct ctc_priv *privptr;
-
- /* Only the first time the ctc_probe gets control */
- if (channel_tab_initialized == 0) {
- channel_init();
-
-
- }
-
- ctc_tab_init();
-
- m = extract_channel_media(dev->name);
- i = extract_channel_id(dev->name);
-
- if (channel_left(m) <=1)
- return -ENODEV;
-
- if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV))
- return -ENODEV;
-
- dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(struct ctc_priv));
- privptr = (struct ctc_priv *) (dev->priv);
-
-
- for (c = 0; c < 2; c++) {
-
- privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
- if (privptr->channel[c].devstat == NULL){
- if (i == WRITE)
- kfree(privptr->channel[READ].devstat);
- return -ENOMEM;
- }
- memset(privptr->channel[c].devstat, 0, sizeof(devstat_t));
-
- if (ctc_no_auto == 0)
- ctc_adapter[m][i].devno[c] = channel_get_next(m);
- else
- ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
-
- if ( ctc_adapter[m][i].devno[c] != -ENODEV){
- rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]),
- (void *)ctc_irq_handler, SA_INTERRUPT, dev->name,
- privptr->channel[c].devstat);
- if (rc) {
- printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
- return -EBUSY;
- }
- } else {
- if (i == WRITE) {
- free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat);
- channel_free(m, ctc_adapter[m][i].devno[READ]);
- kfree(privptr->channel[READ].devstat);
- }
- kfree(privptr->channel[i].devstat);
- return -ENODEV;
- }
- }
-
- privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ];
- privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
- privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
- privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
- privptr->protocol = ctc_adapter[m][i].protocol;
- channel[m].left = channel[m].left - 2;
-
- printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
- dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq,
- privptr->channel[WRITE].devno, privptr->channel[WRITE].irq);
-
- dev->mtu = CTC_DEFAULT_MTU_SIZE;
- dev->hard_start_xmit = ctc_tx;
- dev->open = ctc_open;
- dev->stop = ctc_release;
- dev->get_stats = ctc_stats;
- dev->change_mtu = ctc_change_mtu;
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->type = ARPHRD_SLIP;
- dev->tx_queue_len = 100;
- dev_init_buffers(dev);
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+{
+ int rc;
+ int c;
+ int i;
+ int m;
+ struct ctc_priv *privptr;
+
+ /* Only the first time the ctc_probe gets control */
+ if (channel_tab_initialized == 0) {
+ channel_init();
+ }
+
+ ctc_tab_init();
+
+ m = extract_channel_media(dev->name);
+ i = extract_channel_id(dev->name);
+
+ if (channel_left(m) <= 1)
+ return -ENODEV;
+
+ if (i < 0 || i >= MAX_ADAPTERS)
+ return -ENODEV;
+
+ if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV))
+ return -ENODEV;
+
+ dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL|GFP_DMA);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct ctc_priv));
+ privptr = (struct ctc_priv *) (dev->priv);
+
+
+ for (c = 0; c < 2; c++) {
+ devstat_t *devstat;
+ unsigned int devno;
+
+ privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
+ devstat = privptr->channel[c].devstat;
+ if (devstat == NULL) {
+ if (c == 1) {
+ free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[0]);
+ kfree(privptr->channel[0].devstat);
+ }
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return -ENOMEM;
+ }
+
+ memset(devstat, 0, sizeof(devstat_t));
+
+ if (ctc_no_auto == 0) {
+ ctc_adapter[m][i].devno[c] = channel_get_next(m);
+ devno = ctc_adapter[m][i].devno[c];
+ }
+ else {
+ ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
+ devno = ctc_adapter[m][i].devno[c];
+ }
+
+
+ if (devno != -ENODEV) {
+ rc = request_irq(get_irq_by_devno(devno),
+ ctc_irq_handler, SA_INTERRUPT, dev->name,
+ devstat);
+ if (rc) {
+ printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
+ if (c == 1) {
+ free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]),
+ privptr->channel[0].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[0]);
+ kfree(privptr->channel[0].devstat);
+ }
+ channel_free(m, devno);
+ kfree(devstat);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return -EBUSY;
+ }
+ } else {
+ if (c == 1) {
+ free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[0]);
+ kfree(privptr->channel[0].devstat);
+ }
+ kfree(devstat);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return -ENODEV;
+ }
+ }
+
+ privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ];
+ privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
+ privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
+ privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
+ privptr->channel[READ].dev = privptr->channel[WRITE].dev = dev;
+ privptr->protocol = ctc_adapter[m][i].protocol;
+ channel[m].left = channel[m].left - 2;
+
+ print_banner();
+ printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
+ dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq,
+ privptr->channel[WRITE].devno, privptr->channel[WRITE].irq);
+
+ dev->mtu = CTC_DEFAULT_MTU_SIZE;
+ dev->hard_start_xmit = ctc_tx;
+ dev->open = ctc_open;
+ dev->stop = ctc_release;
+ dev->get_stats = ctc_stats;
+ dev->change_mtu = ctc_change_mtu;
+ dev->hard_header_len = 6;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP;
+ dev->tx_queue_len = 100;
+ dev_init_buffers(dev);
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ ctc_adapter[m][i].netdev = dev;
- return 0;
+ return 0;
}
@@ -867,456 +1060,563 @@
*
*/
-static void inline ccw_check_return_code (net_device *dev, int return_code)
+static void inline ccw_check_return_code (net_device *dev, int return_code, char *caller)
{
- if (return_code != 0) {
- switch (return_code) {
- case -EBUSY:
- printk(KERN_INFO "%s: Busy !\n", dev->name);
- break;
- case -ENODEV:
- printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name);
- break;
- case -EIO:
- printk(KERN_EMERG "%s: Status pending... \n", dev->name);
- break;
- default:
- printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n",
- dev->name, return_code);
- }
- }
+ if (return_code != 0) {
+ switch (return_code) {
+ case -EBUSY:
+ printk(KERN_INFO "%s: %s: Busy !\n", dev->name, caller);
+ break;
+ case -ENODEV:
+ printk(KERN_EMERG "%s: %s: Invalid device called for IO\n", dev->name, caller);
+ break;
+ case -EIO:
+ printk(KERN_EMERG "%s: %s: Status pending... \n", dev->name, caller);
+ break;
+ default:
+ printk(KERN_EMERG "%s: %s: Unknown error in Do_IO %04x\n",
+ dev->name, caller, return_code);
+ }
+ }
}
-static void inline ccw_check_unit_check (net_device *dev, char sense)
+static void inline ccw_check_unit_check (net_device *dev, char sense, char *caller)
{
#ifdef DEBUG
- printk(KERN_INFO "%s: Unit Check with sense code: %02x\n",
- dev->name, sense);
+ printk(KERN_INFO "%s: %s: Unit Check with sense code: %02x\n",
+ dev->name, caller, sense);
#endif
- if (sense & 0x40) {
+ if (sense & 0x40) {
#ifdef DEBUG
- if (sense & 0x01)
- printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name);
- else
- printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name);
-#endif
- } else if (sense & 0x20) {
- if (sense & 0x04)
- printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name);
- else
- printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name);
- } else if (sense & 0x10) {
- if (sense & 0x20)
- printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name);
- else
- printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name);
- }
+ if (sense & 0x01)
+ printk(KERN_DEBUG "%s: %s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name, caller);
+ else
+ printk(KERN_DEBUG "%s: %s: System reset occured (remote side)\n", dev->name, caller);
+#endif
+ } else if (sense & 0x20) {
+ if (sense & 0x04)
+ printk(KERN_WARNING "%s: %s: Data-streaming timeout)\n", dev->name, caller);
+ else
+ printk(KERN_WARNING "%s: %s: Data-transfer parity error\n", dev->name, caller);
+ } else if (sense & 0x10) {
+ if (sense & 0x20)
+ printk(KERN_WARNING "%s: %s: Hardware malfunction (remote side)\n", dev->name, caller);
+ else
+ printk(KERN_WARNING "%s: %s: Read-data parity error (remote side)\n", dev->name, caller);
+ }
}
-
+
static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
{
- int rc = 0;
- __u32 parm;
- __u8 flags = 0x00;
- struct channel *ctc = NULL;
- struct ctc_priv *privptr = NULL;
- net_device *dev = NULL;
-
- /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
- {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */
-
- ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, NULL},
- {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}};
+ int rc = 0;
+ __u32 parm;
+ __u8 flags = 0x00;
+ struct channel *ctc = NULL;
+ struct ctc_priv *privptr = NULL;
+ net_device *dev = NULL;
+
+ /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+ {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */
+
+ static ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, 0},
+ {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, 0}};
- devstat_t *devstat = ((devstat_t *)initparm);
+ devstat_t *devstat = ((devstat_t *)initparm);
- /* Bypass all 'unsolicited interrupts' */
- if (devstat->intparm == 0) {
+ /* Bypass all 'unsolicited interrupts' */
+ if (devstat->intparm == 0) {
#ifdef DEBUG
- printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
- devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
+ printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received cstat: %02x dstat: %02x flag: %02x\n",
+ devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
#endif
- /* FIXME - find the related intparm!!! No IO outstanding!!!! */
- return;
- }
-
- ctc = (struct channel *) (devstat->intparm);
- dev = (net_device *) ctc->dev;
- privptr = dev->priv;
+ /* FIXME - find the related intparm!!! No IO outstanding!!!! */
+ return;
+ }
+
+ ctc = (struct channel *) (devstat->intparm);
+ if(ctc==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler ctc=NULL irq=%d\n",irq);
+ return;
+ }
+
+ dev = (net_device *) ctc->dev;
+ if(dev==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler dev=NULL irq=%d, ctc=0x%p\n",
+ irq, ctc);
+ return;
+ }
+
+ privptr = dev->priv;
+ if(privptr==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler privptr=NULL "
+ "irq=%d, ctc=0x%p, dev=0x%p\n", irq, ctc, privptr);
+ return;
+ }
#ifdef DEBUG
- printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
- dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
+ printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
+ dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
#endif
- /* Check for good subchannel return code, otherwise error message */
- if (devstat->cstat) {
- printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n",
- dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
- return;
- }
+ /* Check for good subchannel return code, otherwise error message */
+ if (devstat->cstat) {
+ printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n",
+ dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
+ return;
+ }
- /* Check the reason-code of a unit check */
- if (devstat->dstat & DEV_STAT_UNIT_CHECK)
- ccw_check_unit_check(dev, devstat->ii.sense.data[0]);
+ /* Check the reason-code of a unit check */
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK)
+ ccw_check_unit_check(dev, devstat->ii.sense.data[0], __FUNCTION__ "()");
- /* State machine to bring the connection up / down and to restart */
+ /* State machine to bring the connection up / down and to restart */
- ctc->last_dstat = devstat->dstat;
+ ctc->last_dstat = devstat->dstat;
- switch (ctc->state) {
+ switch (ctc->state) {
- case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
- wake_up(&ctc->wait); /* wake up ctc_release */
- return;
+ case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_STOP");
+#endif
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_release */
+ return;
- case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
-
- ctc->state = CTC_START_SET_X_MODE;
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- return;
+ case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_HALT_IO");
+#endif
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+
+ ctc->state = CTC_START_SET_X_MODE;
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+ return;
-
- case CTC_START_SET_X_MODE:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) != 0x40) {
- wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */
- return;
- }
- }
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
- ctc->state = CTC_START_SELECT;
+
+ case CTC_START_SET_X_MODE:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SET_X_MODE");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) != 0x40) {
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */
+ return;
+ }
+ }
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+ ctc->state = CTC_START_SELECT;
- case CTC_START_SELECT:
- if (!ctc->flag & CTC_WRITE) {
- ctc->state = CTC_START_READ_TEST;
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- wake_up(&ctc->wait); /* wake up ctc_open (READ) */
-
- } else {
- ctc->state = CTC_START_WRITE_TEST;
- /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].count = 2; /* Transfer only length */
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- }
- return;
-
-
- case CTC_START_READ_TEST:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
- devstat->ii.sense.data[0] == 0 ) {
- init_timer(&ctc->timer);
- ctc->timer.function = (void *)ctc_read_retry;
- ctc->timer.data = (__u32)ctc;
- ctc->timer.expires = jiffies + 10*HZ;
- add_timer(&ctc->timer);
+ case CTC_START_SELECT:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SELECT");
+#endif
+ if(ctc->free_anchor==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_SELECT ctc_free_anchor=NULL "
+ "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
+ return;
+ }
+ if (!(ctc->flag & CTC_WRITE)) {
+ ctc->state = CTC_START_READ_TEST;
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[2]");
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_open (READ) */
+
+ } else {
+ ctc->state = CTC_START_WRITE_TEST;
+ /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[3]");
+ }
+ return;
+
+
+ case CTC_START_READ_TEST:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ_TEST");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+ devstat->ii.sense.data[0] == 0 ) {
+ init_timer(&ctc->timer);
+ ctc->timer.function = ctc_read_retry;
+ ctc->timer.data = (unsigned long)ctc;
+ ctc->timer.expires = jiffies + 10*HZ;
+ add_timer(&ctc->timer);
#ifdef DEBUG
- printk(KERN_DEBUG "%s: read connection restarted\n",dev->name);
+ printk(KERN_DEBUG "%s: read connection restarted\n",dev->name);
#endif
- }
- return;
- }
-
- if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
- if ((devstat->dstat & DEV_STAT_ATTENTION) &&
- (devstat->dstat & DEV_STAT_BUSY)) {
- printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
- }
- wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */
- return;
- }
-
- ctc->state = CTC_START_READ;
- set_bit(0, (void *)&ctc->IO_active);
-
- /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
- /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */
-
-
- case CTC_START_READ:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
- devstat->ii.sense.data[0] == 0 ) {
- privptr->stats.rx_errors++;
+ }
+ return;
+ }
+
+ if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+ if ((devstat->dstat & DEV_STAT_ATTENTION) &&
+ (devstat->dstat & DEV_STAT_BUSY)) {
+ printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
+ }
+ privptr->channel[WRITE].flag |= CTC_WAKEUP;
+ wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */
+ return;
+ }
+
+ ctc->state = CTC_START_READ;
+ set_bit(0, &ctc->IO_active);
+
+ /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
+ /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */
+
+
+ case CTC_START_READ:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+ devstat->ii.sense.data[0] == 0 ) {
+ privptr->stats.rx_errors++;
/* Need protection here cos we are in the read irq */
/* handler the tbusy is for the write subchannel */
ctc_protect_busy(dev);
- ctc_setbit_busy(TB_RETRY,dev);
+ ctc_setbit_busy(TB_RETRY,dev);
ctc_unprotect_busy(dev);
- init_timer(&ctc->timer);
- ctc->timer.function = (void *)ctc_read_retry;
- ctc->timer.data = (__u32)ctc;
- ctc->timer.expires = jiffies + 30*HZ;
- add_timer(&ctc->timer);
- printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
- }
- return;
- }
+ init_timer(&ctc->timer);
+ ctc->timer.function = ctc_read_retry;
+ ctc->timer.data = (unsigned long)ctc;
+ ctc->timer.expires = jiffies + 30*HZ;
+ add_timer(&ctc->timer);
+ printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
+ }
+ return;
+ }
- if(!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
+ if(!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
ctc_protect_busy(dev);
ctc_clearbit_busy(TB_RETRY,dev);
ctc_unprotect_busy(dev);
- ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
+ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
+
+ if (ctc->free_anchor != NULL) {
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[4]");
+ } else {
+ clear_bit(0, &ctc->IO_active);
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
+#endif
+ }
+
+ if (test_and_set_bit(CTC_BH_ACTIVE, &ctc->flag_a) == 0) {
+ queue_task(&ctc->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ return;
- if (ctc->free_anchor != NULL) {
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- } else {
- clear_bit(0, (void *)&ctc->IO_active);
-#ifdef DEBUG
- printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
-#endif
- }
-
- if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) {
- queue_task(&ctc->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- }
- return;
-
-
- case CTC_START_WRITE_TEST:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
- devstat->ii.sense.data[0] == 0 ) {
- init_timer(&ctc->timer);
- ctc->timer.function = (void *)ctc_write_retry;
- ctc->timer.data = (__u32)ctc;
- ctc->timer.expires = jiffies + 10*HZ;
- add_timer(&ctc->timer);
-#ifdef DEBUG
- printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
-#endif
- }
- return;
- }
-
- ctc->state = CTC_START_WRITE;
- wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */
- return;
+
+ case CTC_START_WRITE_TEST:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE_TEST");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+ devstat->ii.sense.data[0] == 0 ) {
+ init_timer(&ctc->timer);
+ ctc->timer.function = ctc_write_retry;
+ ctc->timer.data = (unsigned long)ctc;
+ ctc->timer.expires = jiffies + 10*HZ;
+ add_timer(&ctc->timer);
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
+#endif
+ }
+ return;
+ }
+
+ ctc->state = CTC_START_WRITE;
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */
+ return;
- case CTC_START_WRITE:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- privptr->stats.tx_errors += ctc->proc_anchor->packets;
-#ifdef DEBUG
- printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
-#endif
- } else {
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
- privptr->stats.tx_packets += ctc->proc_anchor->packets;
- }
-
- ctc->proc_anchor->block->length = 0;
- ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
- ctc_clearbit_busy(TB_NOBUFFER,dev);
- if (ctc->proc_anchor != NULL) {
-#ifdef DEBUG
- printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name);
-#endif
- ctc->ccw[1].count = ctc->proc_anchor->block->length;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- dev->trans_start = jiffies;
- return;
-
- }
-
- if (ctc->free_anchor->block->length != 0) {
- if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {
- /* set transmission to busy */
- ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
- ctc_clearbit_busy(TB_TX,dev);
-#ifdef DEBUG
- printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name);
-#endif
- ctc->ccw[1].count = ctc->proc_anchor->block->length;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- dev->trans_start = jiffies;
- return;
- }
- }
+ case CTC_START_WRITE:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ privptr->stats.tx_errors += ctc->proc_anchor->packets;
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
+#endif
+ } else {
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+ privptr->stats.tx_packets += ctc->proc_anchor->packets;
+ }
+
+ ctc->proc_anchor->block->length = 0;
+ ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
+ ctc_clearbit_busy(TB_NOBUFFER, dev);
+ if (ctc->proc_anchor != NULL) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name);
+#endif
+ ctc->ccw[1].count = ctc->proc_anchor->block->length;
+ ctc->ccw[1].cda = __pa(ctc->proc_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[5]");
+ dev->trans_start = jiffies;
+ return;
+
+ }
+ if (ctc->free_anchor==NULL) {
+ printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_WRITE ctc_free_anchor=NULL "
+ "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
+ return;
+ }
+ if (ctc->free_anchor->block->length != 0) {
+ if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {
+ /* set transmission to busy */
+ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
+ ctc_clearbit_busy(TB_TX,dev);
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name);
+#endif
+ ctc->ccw[1].count = ctc->proc_anchor->block->length;
+ ctc->ccw[1].cda = __pa(ctc->proc_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[6]");
+ dev->trans_start = jiffies;
+ return;
+ }
+ }
- clear_bit(0, (void *)&ctc->IO_active); /* set by ctc_tx or ctc_bh */
- return;
+ clear_bit(0, &ctc->IO_active); /* set by ctc_tx or ctc_bh */
+ return;
- default:
- printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
- return;
- }
+ default:
+ printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
+ return;
+ }
}
-static void ctc_irq_bh (struct channel *ctc)
+static void ctc_irq_bh (void *data)
{
- int rc = 0;
- __u16 data_len;
- __u32 parm;
-
- __u8 flags = 0x00;
- __u32 saveflags;
- net_device *dev;
- struct ctc_priv *privptr;
- struct packet *lp;
- struct sk_buff *skb;
+ struct channel *ctc = (struct channel *) data;
+ net_device *dev = (net_device *) ctc->dev;
+ struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
+
+ int rc = 0;
+ __u16 data_len;
+ __u32 parm;
+
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ struct block *block;
+ struct packet *lp;
+ struct sk_buff *skb;
- dev = (net_device *) ctc->dev;
- privptr = (struct ctc_priv *) dev->priv;
#ifdef DEBUG
- printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
+ printk(KERN_DEBUG "%s: %s(): initial_block_received = %d\n" ,dev->name, __FUNCTION__, ctc->initial_block_received);
+ printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
#endif
- while (ctc->proc_anchor != NULL) {
-
- if (ctc->proc_anchor->block->length != 0) {
-
- lp = &ctc->proc_anchor->block->data;
- while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) {
- data_len = lp->length - PACKET_HEADER_LENGTH;
- skb = dev_alloc_skb(data_len);
- if (skb) {
- memcpy(skb_put(skb, data_len),&lp->data, data_len);
- skb->mac.raw = skb->data;
- skb->dev = dev;
- skb->protocol = htons(ETH_P_IP);
- skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */
- netif_rx(skb);
- privptr->stats.rx_packets++;
- } else {
- privptr->stats.rx_dropped++;
- printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
- }
- (__u8 *)lp += lp->length;
- }
- }
+ while (ctc->proc_anchor != NULL) {
+ block = ctc->proc_anchor->block;
+ if (block->length < BLOCK_HEADER_LENGTH) {
+ if(block->length == 0 && !ctc->initial_block_received)
+ ctc->initial_block_received = 1;
+ else
+ printk(KERN_INFO "%s: %s(): discarding block at 0x%p: "
+ "block length=%d<%d=block header length\n",
+ dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH);
+ }
+ else {
+ lp = &block->data;
+ while ((__u8 *) lp < (__u8 *) block + block->length) {
+ if(lp->length < PACKET_HEADER_LENGTH) {
+ printk(KERN_INFO "%s: %s(): discarding rest of block at 0x%p (block length=%d:) "
+ "packet at 0x%p, packet length=%d<%d=packet header length\n",
+ dev->name, __FUNCTION__,
+ block, block->length, lp, lp->length, PACKET_HEADER_LENGTH);
+ break;
+ }
+
+ data_len = lp->length - PACKET_HEADER_LENGTH;
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): block=0x%p, block->length=%d, lp=0x%p, "
+ "lp->length=%d, data_len=%d\n",
+ dev->name, __FUNCTION__, block, block->length, lp, lp->length, data_len);
+#endif
+ skb = dev_alloc_skb(data_len);
+ if (skb) {
+ memcpy(skb_put(skb, data_len),&lp->data, data_len);
+ skb->mac.raw = skb->data;
+ skb->dev = dev;
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */
+ netif_rx(skb);
+ privptr->stats.rx_packets++;
+ } else {
+ privptr->stats.rx_dropped++;
+ printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
+ }
+ (__u8 *)lp += lp->length;
+ }
+ }
- s390irq_spin_lock_irqsave(ctc->irq, saveflags);
- ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
+ s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+ ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
- if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) {
+ if (test_and_set_bit(0, &ctc->IO_active) == 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
+#endif
+ if(ctc->free_anchor==NULL || ctc->free_anchor->block==NULL)
+ {
+ printk(KERN_CRIT "ctc: bad anchor free_anchor "
+ "ctc=0x%p, ctc->free_anchor=0x%p, ctc->irq=%d\n",
+ ctc, ctc->free_anchor, ctc->irq);
+ }
+ else
+ {
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+ }
+ }
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+ }
+ clear_bit(CTC_BH_ACTIVE, &ctc->flag_a);
#ifdef DEBUG
- printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
+ printk(KERN_DEBUG "%s: end bh routine - state-%02x\n" ,dev->name, ctc->state);
#endif
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- }
- s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
- }
- clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a);
- return;
+ return;
}
-static void ctc_read_retry (struct channel *ctc)
+static void ctc_read_retry (unsigned long data)
{
- int rc = 0;
- __u32 parm;
- __u8 flags = 0x00;
- __u32 saveflags;
- net_device *dev;
+ struct channel *ctc = (struct channel *) data;
+ net_device *dev = (net_device *) ctc->dev;
+ int rc = 0;
+ __u32 parm;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+
- dev = (net_device *) ctc->dev;
-
#ifdef DEBUG
- printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state);
-#endif
- if (ctc->state == CTC_STOP)
- return;
- s390irq_spin_lock_irqsave(ctc->irq, saveflags);
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- return;
+ printk(KERN_DEBUG "%s: read retry - state-%02x\n",
+ dev->name, ctc->state);
+#endif
+ s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+ if (ctc->state != CTC_STOP) {
+ if (!ctc->free_anchor) {
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+ printk(KERN_WARNING
+ "%s: %s(): ctc->free_anchor=NULL, ctc=0x%p\n",
+ dev->name, __FUNCTION__, ctc);
+ return;
+ }
+
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
+ }
+
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+ return;
}
-static void ctc_write_retry (struct channel *ctc)
+static void ctc_write_retry (unsigned long data)
{
- int rc = 0;
- __u32 parm;
- __u8 flags = 0x00;
- __u32 saveflags;
- net_device *dev;
+ struct channel *ctc = (struct channel *) data;
+ net_device *dev = (net_device *) ctc->dev;
+ int rc = 0;
+ __u32 parm;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
- dev = (net_device *) ctc->dev;
#ifdef DEBUG
- printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
-#endif
- if (ctc->state == CTC_STOP)
- return;
-
- while (ctc->proc_anchor != NULL) {
- ctc->proc_anchor->block->length = 0;
- ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
- }
-
- ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
- s390irq_spin_lock_irqsave(ctc->irq, saveflags);
- ctc->ccw[1].count = 2;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- return;
+ printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
+#endif
+
+ if (ctc->proc_anchor != NULL) {
+ printk(KERN_WARNING "%s: %s(): ctc->proc_anchor != NULL\n" ,dev->name, __FUNCTION__);
+ }
+
+ s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+
+ if (ctc->state != CTC_STOP)
+ {
+ ctc->ccw[1].count = 2;
+ ctc->ccw[1].cda = __pa(ctc->proc_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ }
+
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+ return;
}
@@ -1327,123 +1627,139 @@
*/
static int ctc_open(net_device *dev)
{
- int rc;
- int i;
- int j;
- __u8 flags = 0x00;
- __u32 saveflags;
- __u32 parm;
- struct ctc_priv *privptr;
- DECLARE_WAITQUEUE(wait, current);
- struct timer_list timer;
-
-
- ctc_set_busy(dev);
-
- privptr = (struct ctc_priv *) (dev->priv);
-
- privptr->channel[READ].flag = 0x00;
- privptr->channel[WRITE].flag = CTC_WRITE;
-
- for (i = 0; i < 2; i++) {
- for (j = 0; j < CTC_BLOCKS; j++) {
- rc = ctc_buffer_alloc(&privptr->channel[i]);
- if (rc != 0)
- return -ENOMEM;
- }
- init_waitqueue_head(&privptr->channel[i].wait);
- privptr->channel[i].tq.next = NULL;
- privptr->channel[i].tq.sync = 0;
- privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh;
- privptr->channel[i].tq.data = &privptr->channel[i];
-
- privptr->channel[i].dev = dev;
-
- privptr->channel[i].flag_a = 0;
- privptr->channel[i].IO_active = 0;
-
- privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE;
- privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- privptr->channel[i].ccw[0].count = 0;
- privptr->channel[i].ccw[0].cda = NULL;
- if (i == READ) {
- privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ;
- privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI;
- privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */
- privptr->channel[i].ccw[1].cda = NULL;
- } else {
- privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
- privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- privptr->channel[i].ccw[1].count = 0;
- privptr->channel[i].ccw[1].cda = NULL;
- }
- privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */
- privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI;
- privptr->channel[i].ccw[2].count = 0;
- privptr->channel[i].ccw[2].cda = NULL;
-
- privptr->channel[i].flag &= ~CTC_TIMER;
- init_timer(&timer);
- timer.function = (void *)ctc_timer;
- timer.data = (__u32)&privptr->channel[i];
- timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */
- add_timer(&timer);
-
- s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
- parm = (unsigned long) &privptr->channel[i];
- privptr->channel[i].state = CTC_START_HALT_IO;
- rc = halt_IO(privptr->channel[i].irq, parm, flags);
- add_wait_queue(&privptr->channel[i].wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
- s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
- schedule();
- remove_wait_queue(&privptr->channel[i].wait, &wait);
- if(rc != 0)
- ccw_check_return_code(dev, rc);
- if((privptr->channel[i].flag & CTC_TIMER) == 0x00)
- del_timer(&timer);
- }
-
- if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
- ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
- (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
+ int rc, wait_rc;
+ int i, ii;
+ int j;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ __u32 parm;
+ struct ctc_priv *privptr;
+ struct timer_list timer;
+
+
+ ctc_set_busy(dev);
+
+ privptr = (struct ctc_priv *) (dev->priv);
+
+ privptr->channel[READ].flag = 0x00;
+ privptr->channel[WRITE].flag = CTC_WRITE;
+
+ for (i = 0; i < 2; i++) {
+ privptr->channel[i].free_anchor = NULL;
+ privptr->channel[i].proc_anchor = NULL;;
+ for (j = 0; j < CTC_BLOCKS; j++) {
+ rc = ctc_buffer_alloc(&privptr->channel[i]);
+ if (rc != 0)
+ return -ENOMEM;
+ }
+ init_waitqueue_head(&privptr->channel[i].wait);
+ privptr->channel[i].tq.next = NULL;
+ privptr->channel[i].tq.sync = 0;
+ privptr->channel[i].tq.routine = ctc_irq_bh;
+ privptr->channel[i].tq.data = &privptr->channel[i];
+
+ privptr->channel[i].initial_block_received = 0;
+
+ privptr->channel[i].dev = dev;
+
+ privptr->channel[i].flag_a = 0;
+ privptr->channel[i].IO_active = 0;
+
+ privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE;
+ privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ privptr->channel[i].ccw[0].count = 0;
+ privptr->channel[i].ccw[0].cda = 0;
+ if (i == READ) {
+ privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ;
+ privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI;
+ privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */
+ privptr->channel[i].ccw[1].cda = 0;
+ } else {
+ privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
+ privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ privptr->channel[i].ccw[1].count = 0;
+ privptr->channel[i].ccw[1].cda = 0;
+ }
+ privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */
+ privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI;
+ privptr->channel[i].ccw[2].count = 0;
+ privptr->channel[i].ccw[2].cda = 0;
+
+ privptr->channel[i].flag &= ~(CTC_TIMER | CTC_WAKEUP);
+ init_timer(&timer);
+ timer.function = ctc_timer;
+ timer.data = (unsigned long)&privptr->channel[i];
+ timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */
+ add_timer(&timer);
+
+ s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+ parm = (unsigned long) &privptr->channel[i];
+ privptr->channel[i].state = CTC_START_HALT_IO;
+ rc = halt_IO(privptr->channel[i].irq, parm, flags);
+ s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
+
+ wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+ del_timer(&timer);
+
+ if(rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+ if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */
+ for (ii=0; ii<=i; ii++) {
+
+ del_timer(&privptr->channel[ii].timer);
+
+ for (j=0; privptr->channel[ii].free_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_free(&privptr->channel[ii]);
+
+ if (privptr->channel[ii].free_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+ }
+ return -ERESTARTSYS;
+ }
+ }
+
+ if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
+ ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
+ (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
#ifdef DEBUG
- printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n",
- dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+ printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n",
+ dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
#endif
- printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
-
- for (i = 0; i < 2; i++) {
- /* s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
- parm = (unsigned long) &privptr->channel[i];
- privptr->channel[i].state = CTC_STOP;
- rc = halt_IO(privptr->channel[i].irq, parm, flags); /
- s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
- if (rc != 0)
- ccw_check_return_code(dev, rc); */
- for (j = 0; j < CTC_BLOCKS; j++)
- ctc_buffer_free(&privptr->channel[i]);
- }
- return -EIO;
- }
-
- printk(KERN_INFO "%s: connected with remote side\n",dev->name);
- ctc_clear_busy(dev);
- return 0;
+ printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
+
+ for (i = 0; i < 2; i++) {
+ del_timer(&privptr->channel[i].timer);
+
+ for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_free(&privptr->channel[i]);
+
+ if (privptr->channel[i].free_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+ }
+ return -EIO;
+ }
+
+ printk(KERN_INFO "%s: connected with remote side\n",dev->name);
+ ctc_clear_busy(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
}
-static void ctc_timer (struct channel *ctc)
-{
-#ifdef DEBUG
- net_device *dev;
-
- dev = (net_device *) ctc->dev;
- printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
-#endif
- ctc->flag |= CTC_TIMER;
- wake_up(&ctc->wait);
- return;
+static void ctc_timer (unsigned long data)
+{
+ struct channel *ctc = (struct channel *) data;
+#ifdef DEBUG
+ net_device *dev = (net_device *) ctc->dev;
+ printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
+#endif
+ ctc->flag |= (CTC_TIMER|CTC_WAKEUP);
+ wake_up(&ctc->wait);
+ return;
}
/*
@@ -1452,49 +1768,75 @@
*/
static int ctc_release(net_device *dev)
{
- int rc;
- int i;
- int j;
- __u8 flags = 0x00;
- __u32 saveflags;
- __u32 parm;
- struct ctc_priv *privptr;
- DECLARE_WAITQUEUE(wait, current);
-
- privptr = (struct ctc_priv *) dev->priv;
-
- ctc_protect_busy_irqsave(dev,saveflags);
- ctc_setbit_busy(TB_STOP,dev);
- ctc_unprotect_busy_irqrestore(dev,flags);
- for (i = 0; i < 2; i++) {
- s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
- del_timer(&privptr->channel[READ].timer);
- privptr->channel[i].state = CTC_STOP;
- parm = (__u32) &privptr->channel[i];
- rc = halt_IO (privptr->channel[i].irq, parm, flags );
- add_wait_queue(&privptr->channel[i].wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
- s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
- schedule();
- remove_wait_queue(&privptr->channel[i].wait, &wait);
- if (rc != 0) {
- ccw_check_return_code(dev, rc);
- }
-
- for (j = 0; j < CTC_BLOCKS; j++) {
- ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor);
- ctc_buffer_free(&privptr->channel[i]);
- }
- }
-
- if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
- ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
- printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n",
- dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
- return -EIO;
- }
+ int rc;
+ int i;
+ int j;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ __u32 parm;
+ struct ctc_priv *privptr;
+ struct timer_list timer;
+
+ privptr = (struct ctc_priv *) dev->priv;
+
+ ctc_protect_busy_irqsave(dev, saveflags);
+ ctc_setbit_busy(TB_STOP,dev);
+ ctc_unprotect_busy_irqrestore(dev, saveflags);
+
+ for (i = 0; i < 2; i++) {
+ privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER);
+ init_timer(&timer);
+ timer.function = ctc_timer;
+ timer.data = (unsigned long)&privptr->channel[i];
+ timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */
+ add_timer(&timer);
+
+ s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+ del_timer(&privptr->channel[i].timer);
+ privptr->channel[i].state = CTC_STOP;
+ parm = (__u32)(long) &privptr->channel[i];
+ rc = halt_IO (privptr->channel[i].irq, parm, flags );
+ s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
+
+ wait_event(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+ del_timer(&timer);
+
+ if (rc != 0) {
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+ }
+
+ if(privptr->channel[i].flag & CTC_TIMER)
+ {
+ printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n",
+ dev->name, __FUNCTION__);
+ }
+
+
+ for (j=0; privptr->channel[i].proc_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor, dev);
+
+ if (privptr->channel[i].proc_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to move more than maximal number %d of blocks to free list\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+
+ for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_free(&privptr->channel[i]);
+
+ if (privptr->channel[i].free_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+ }
+
+ if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
+ ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+ printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n",
+ dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+ return -EIO;
+ }
- return 0;
+ MOD_DEC_USE_COUNT;
+ return 0;
}
@@ -1505,80 +1847,80 @@
*/
static int ctc_tx(struct sk_buff *skb, net_device *dev)
{
- int rc=0,rc2;
- __u32 parm;
- __u8 flags = 0x00;
- __u32 saveflags;
- struct ctc_priv *privptr;
- struct packet *lp;
-
+ int rc=0,rc2;
+ __u32 parm;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ struct ctc_priv *privptr;
+ struct packet *lp;
+
- privptr = (struct ctc_priv *) (dev->priv);
+ privptr = (struct ctc_priv *) (dev->priv);
- if (skb == NULL) {
- printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
- privptr->stats.tx_dropped++;
- return -EIO;
- }
-
- s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
- if (ctc_check_busy(dev)) {
- rc=-EBUSY;
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
+ privptr->stats.tx_dropped++;
+ return -EIO;
+ }
+
+ s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
+ if (ctc_check_busy(dev)) {
+ rc=-EBUSY;
goto Done;
- }
+ }
- if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */
- rc=-EBUSY;
+ if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */
+ rc=-EBUSY;
goto Done;
- }
+ }
- if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) {
+ if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) {
#ifdef DEBUG
- printk(KERN_DEBUG "%s: early swap\n", dev->name);
+ printk(KERN_DEBUG "%s: early swap\n", dev->name);
#endif
-
- ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor);
- if (privptr->channel[WRITE].free_anchor == NULL){
- ctc_setbit_busy(TB_NOBUFFER,dev);
- rc=-EBUSY;
+
+ ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor, dev);
+ if (privptr->channel[WRITE].free_anchor == NULL){
+ ctc_setbit_busy(TB_NOBUFFER,dev);
+ rc=-EBUSY;
goto Done2;
- }
- }
-
- if (privptr->channel[WRITE].free_anchor->block->length == 0) {
- privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH;
- privptr->channel[WRITE].free_anchor->packets = 0;
- }
-
-
- (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + privptr->channel[WRITE].free_anchor->block->length;
- privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
- lp->length = skb->len + PACKET_HEADER_LENGTH;
- lp->type = 0x0800;
- lp->unused = 0;
- memcpy(&lp->data, skb->data, skb->len);
- (__u8 *) lp += lp->length;
- lp->length = 0;
- dev_kfree_skb(skb);
- privptr->channel[WRITE].free_anchor->packets++;
-
- if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) {
- ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor);
- privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
- privptr->channel[WRITE].ccw[1].cda = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block);
- parm = (__u32) &privptr->channel[WRITE];
- rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
- if (rc2 != 0)
- ccw_check_return_code(dev, rc2);
- dev->trans_start = jiffies;
- }
- if (privptr->channel[WRITE].free_anchor == NULL)
- ctc_setbit_busy(TB_NOBUFFER,dev);
+ }
+ }
+
+ if (privptr->channel[WRITE].free_anchor->block->length == 0) {
+ privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH;
+ privptr->channel[WRITE].free_anchor->packets = 0;
+ }
+
+
+ (__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length;
+ privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
+ lp->length = skb->len + PACKET_HEADER_LENGTH;
+ lp->type = 0x0800;
+ lp->unused = 0;
+ memcpy(&lp->data, skb->data, skb->len);
+ (__u8 *) lp += lp->length;
+ lp->length = 0;
+ dev_kfree_skb(skb);
+ privptr->channel[WRITE].free_anchor->packets++;
+
+ if (test_and_set_bit(0, &privptr->channel[WRITE].IO_active) == 0) {
+ ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor, dev);
+ privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
+ privptr->channel[WRITE].ccw[1].cda = __pa(privptr->channel[WRITE].proc_anchor->block);
+ parm = (__u32)(long) &privptr->channel[WRITE];
+ rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
+ if (rc2 != 0)
+ ccw_check_return_code(dev, rc2, __FUNCTION__ "()[1]");
+ dev->trans_start = jiffies;
+ }
+ if (privptr->channel[WRITE].free_anchor == NULL)
+ ctc_setbit_busy(TB_NOBUFFER,dev);
Done2:
- ctc_clearbit_busy(TB_TX,dev);
+ ctc_clearbit_busy(TB_TX,dev);
Done:
s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
- return(rc);
+ return(rc);
}
@@ -1586,15 +1928,15 @@
* ctc_change_mtu
*
* S/390 can handle MTU sizes from 576 to 32760 for VM, VSE
- * 576 to 65527 for OS/390
+ * 576 to 65527 for OS/390
*
*/
static int ctc_change_mtu(net_device *dev, int new_mtu)
{
- if ((new_mtu < 576) || (new_mtu > 65528))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
+ if ((new_mtu < 576) || (new_mtu > 65528))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
}
@@ -1604,18 +1946,129 @@
*/
struct net_device_stats *ctc_stats(net_device *dev)
{
- struct ctc_priv *privptr;
+ struct ctc_priv *privptr;
- privptr = dev->priv;
- return &privptr->stats;
+ privptr = dev->priv;
+ return &privptr->stats;
}
-
/* Module code goes here */
-/*
- free_irq(privptr->channel[i].irq, privptr->channel[i].devstat);
- kfree(privptr->channel[i].devstat);
+#ifdef MODULE
+void cleanup_module(void) {
+ int m;
+ int i;
+ int c;
+
+ /* we are called if all interfaces are down only, so no need
+ * to bother around with locking stuff
+ */
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (i = 0; i < MAX_ADAPTERS; i++)
+ if (ctc_adapter[m][i].netdev) {
+ struct ctc_priv *privptr = ctc_adapter[m][i].netdev->priv;
+
+ unregister_netdev(ctc_adapter[m][i].netdev);
+ for (c = 0; c < 2; c++) {
+ free_irq(privptr->channel[c].irq, privptr->channel[c].devstat);
+ kfree(privptr->channel[c].devstat);
+ }
+ kfree(privptr);
+ kfree(ctc_adapter[m][i].netdev);
+ }
+ }
+ printk(KERN_INFO "CTC driver unloaded\n");
+}
+
+static char *parse_opts(char *str, int *ints) {
+ char *cur = str;
+ int i = 1;
+
+ while (cur && (*cur == '-' || isdigit(*cur)) && i <= 10) {
+ ints[i++] = simple_strtoul(cur, NULL, 0);
+ if ((cur = strchr(cur, ',')) != NULL)
+ cur++;
+ }
+ ints[0] = i - 1;
+ return(cur);
+}
+
+int init_module(void) {
+ char *p = setup; /* This string is set by insmod, it is writeable */
+ int cnt;
+ int itype;
+ int activated;
+ int ints[10];
+
+ print_banner();
+
+ /**
+ * Parse setup string just like in init/main.c
+ */
+ while (p && *p) {
+ char *q = strstr(p, "ctc=");
+ if (q) {
+ /**
+ * Found "ctc=" in string
+ */
+ q += 4;
+ if ((p = parse_opts(q, ints))) {
+ /**
+ * p is now pointing to the first non-number parameter
+ *
+ */
+ if ((q = strchr(p, ' ')))
+ *q = '\0';
+ ctc_setup(p, ints);
+ if (q)
+ p = q + 1;
+ else
+ p = NULL;
+ }
+ } else
+ p = NULL;
+ }
+
+ activated = 0;
+ for (itype = 0; itype < 2; itype++) {
+ cnt = 0;
+ do {
+ net_device *dev = kmalloc(sizeof(net_device) + 11 /* name + trailing zero */ , GFP_KERNEL);
+ if (!dev) {
+ return -ENOMEM;
+ }
+ memset((unsigned char *)dev, 0, sizeof(net_device));
+ dev->name = (unsigned char *)dev + sizeof(net_device);
+ sprintf(dev->name, "%s%d", (itype) ? "escon" : "ctc", cnt++);
+ if (ctc_probe(dev) == 0) {
+ if (register_netdev(dev) != 0) {
+ struct ctc_priv *privptr = dev->priv;
+ int m = extract_channel_media(dev->name);
+ int i = extract_channel_id(dev->name);
+
+ printk(KERN_WARNING "ctc: Couldn't register %s\n", dev->name);
+ free_irq(privptr->channel[READ].irq, privptr->channel[READ].devstat);
+ kfree(privptr->channel[READ].devstat);
+ free_irq(privptr->channel[WRITE].irq, privptr->channel[WRITE].devstat);
+ kfree(privptr->channel[WRITE].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[READ]);
+ channel_free(m, ctc_adapter[m][i].devno[WRITE]);
+ kfree(dev->priv);
+ kfree(dev);
+ } else
+ activated++;
+ } else {
+ kfree(dev);
+ cnt = MAX_ADAPTERS;
+ }
+ } while (cnt < MAX_ADAPTERS);
+ }
+ if (!activated) {
+ printk(KERN_WARNING "ctc: No devices registered\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+#endif
-*/
/* --- This is the END my friend --- */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)