patch-2.2.16 linux/drivers/s390/net/ctc.c

Next file: linux/drivers/s390/net/iucv.c
Previous file: linux/drivers/s390/misc/Makefile
Back to the patch index
Back to the overall index

diff -urN v2.2.15/linux/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
@@ -3,9 +3,12 @@
  *    CTC / ESCON network driver
  *
  *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    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 
@@ -39,8 +42,12 @@
  *            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  
  */
-
+#include <linux/version.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <linux/errno.h>
@@ -76,7 +83,7 @@
         #define KERN_WARNING KERN_EMERG
         #define KERN_DEBUG   KERN_EMERG
 #endif  
-//#undef DEBUG
+
 
 #define CCW_CMD_WRITE           0x01
 #define CCW_CMD_READ            0x02
@@ -161,6 +168,15 @@
         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;
@@ -172,8 +188,8 @@
         struct buffer       *free_anchor;
         struct buffer       *proc_anchor;
         devstat_t           *devstat;
-        struct device       *dev;      /* backward pointer to the network device */ 
-        struct wait_queue   *wait;
+        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 */
@@ -186,7 +202,10 @@
 
 
 struct ctc_priv {                                                                    
-        struct enet_statistics   stats;
+        struct net_device_stats  stats;
+#if LINUX_VERSION_CODE>=0x02032D
+	int                      tbusy;
+#endif
         struct channel           channel[2]; 
         __u16                    protocol;
 };  
@@ -210,6 +229,99 @@
         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);
@@ -219,16 +331,15 @@
 
 
 /* Functions for the DEV methods */
-void ctc_setup(char *dev_name, int *ints);
-int ctc_probe(struct device *dev);
+int ctc_probe(net_device *dev);
  
 
-static int ctc_open(struct device *dev); 
+static int ctc_open(net_device *dev); 
 static void ctc_timer (struct channel *ctc);
-static int ctc_release(struct device *dev);
-static int ctc_tx(struct sk_buff *skb, struct device *dev);
-static int ctc_change_mtu(struct device *dev, int new_mtu);
-struct net_device_stats* ctc_stats(struct device *dev); 
+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); 
 
 
 /*
@@ -573,17 +684,28 @@
  *           0xnnnn is the cu number  write 
  *           ctcx can be ctc0 to ctc7 or escon0 to escon7 
  */
-void ctc_setup(char *dev_name, int *ints)
+#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;
-
+#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
+#endif
         ctc_tab_init();
         
         ctc_no_auto = 1;
 
         if (!strcmp(dev_name,"noauto")) { 
                 printk(KERN_INFO "ctc: automatic channel selection deactivated\n");
-                return;
+                ctc_setup_return;
         }
 
         tmp.devno[WRITE] = -ENODEV;
@@ -605,30 +727,32 @@
                                 break;    
                         } else {
                                 printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
-                                return;
+                                ctc_setup_return;
                         }
                         break;
 
                 default: 
                         printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
-                        return;
+                        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  
-        return;
+        ctc_setup_return;
         
 }
-
+#if LINUX_VERSION_CODE>=0x020300
+__setup("ctc=", ctc_setup);
+#endif
 
 /*
  *   ctc_probe 
  *      this function is called for each channel network device, 
  *      which is defined in the /init/main.c 
  */
-int ctc_probe(struct device *dev)
+int ctc_probe(net_device *dev)
 {       
         int                rc;
         int                c;
@@ -729,7 +853,7 @@
  *
  */
 
-static void inline ccw_check_return_code (struct device *dev, int return_code)
+static void inline ccw_check_return_code (net_device *dev, int return_code)
 {
         if (return_code != 0) {
                 switch (return_code) {
@@ -750,7 +874,7 @@
 } 
 
 
-static void inline ccw_check_unit_check (struct device *dev, char sense)
+static void inline ccw_check_unit_check (net_device *dev, char sense)
 {
 #ifdef DEBUG
         printk(KERN_INFO "%s: Unit Check with sense code: %02x\n",
@@ -786,17 +910,17 @@
         __u8              flags = 0x00;
         struct  channel   *ctc = NULL;
         struct  ctc_priv  *privptr = NULL;
-        struct  device    *dev = 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}}; 
 
         devstat_t *devstat = ((devstat_t *)initparm);
 
-        /* Bypass all 'unsolited interrupts' */
+        /* Bypass all 'unsolicited interrupts' */
         if (devstat->intparm == 0) {
 #ifdef DEBUG
-                printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
+                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);
 #endif 
                 /* FIXME - find the related intparm!!! No IO outstanding!!!! */
@@ -804,7 +928,7 @@
         }
 
         ctc = (struct channel *) (devstat->intparm);
-        dev = (struct device *) ctc->dev;
+        dev = (net_device *) ctc->dev;
         privptr = dev->priv;
 
 #ifdef DEBUG
@@ -814,8 +938,8 @@
 
         /* Check for good subchannel return code, otherwise error message */
         if (devstat->cstat) {
-                printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n", 
-                    dev->name, ctc->devno, 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;
         }
 
@@ -925,7 +1049,11 @@
                                     (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
                                     devstat->ii.sense.data[0] == 0               ) {
                                         privptr->stats.rx_errors++;
-                                        set_bit(TB_RETRY, (void *)&dev->tbusy);
+					/* 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_unprotect_busy(dev);
                                         init_timer(&ctc->timer);
                                         ctc->timer.function = (void *)ctc_read_retry; 
                                         ctc->timer.data = (__u32)ctc;
@@ -938,9 +1066,9 @@
 
                         if(!devstat->flag & DEVSTAT_FINAL_STATUS)
                                 return; 
-
-                        clear_bit(TB_RETRY, (void *)&dev->tbusy);
-                        
+			ctc_protect_busy(dev);
+			ctc_clearbit_busy(TB_RETRY,dev);
+			ctc_unprotect_busy(dev);
                         ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
 
                         if (ctc->free_anchor != NULL) {  
@@ -999,8 +1127,7 @@
 
                         ctc->proc_anchor->block->length = 0;
                         ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
-                        clear_bit(TB_NOBUFFER, (void *)&dev->tbusy);      
-
+                        ctc_clearbit_busy(TB_NOBUFFER,dev);      
                         if (ctc->proc_anchor != NULL) {  
 #ifdef DEBUG
                                 printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); 
@@ -1017,9 +1144,10 @@
                         }
 
                         if (ctc->free_anchor->block->length != 0) {
-                                if (test_and_set_bit(TB_TX, (void *)&dev->tbusy) == 0) {     /* set transmission to busy */
+                                if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {     
+                                       /* set transmission to busy */
                                         ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
-                                        clear_bit(TB_TX, (void *)&dev->tbusy);
+                                        ctc_clearbit_busy(TB_TX,dev);
 #ifdef DEBUG
                                         printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); 
 #endif
@@ -1053,12 +1181,12 @@
 
         __u8               flags = 0x00;
         __u32              saveflags;
-        struct device      *dev;
+        net_device  *dev;
         struct ctc_priv    *privptr;             
         struct packet      *lp;
         struct sk_buff     *skb;
 
-        dev = (struct device *) ctc->dev; 
+        dev = (net_device *) ctc->dev; 
         privptr = (struct ctc_priv *) dev->priv; 
    
 #ifdef DEBUG
@@ -1113,13 +1241,15 @@
         __u32              parm;
         __u8               flags = 0x00;
         __u32              saveflags;
-        struct device      *dev;
+        net_device  *dev;
 
-        dev = (struct device *) ctc->dev; 
+        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->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
         parm = (__u32) ctc; 
@@ -1137,13 +1267,15 @@
         __u32              parm;
         __u8               flags = 0x00;
         __u32              saveflags;
-        struct device      *dev;
+        net_device  *dev;
 
-        dev = (struct device *) ctc->dev; 
+        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;
         s390irq_spin_lock_irqsave(ctc->irq, saveflags);
         ctc->ccw[1].count = 0;
         ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
@@ -1161,7 +1293,7 @@
  *   ctc_open
  *
  */
-static int ctc_open(struct device *dev)
+static int ctc_open(net_device *dev)
 {
         int                rc;
         int                i;
@@ -1170,12 +1302,11 @@
         __u32              saveflags;
         __u32              parm;
         struct ctc_priv    *privptr;
-        struct wait_queue  wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
         struct timer_list  timer;
 
 
-        dev->tbusy = 1;
-        dev->start = 0;
+        ctc_set_busy(dev);
 
         privptr = (struct ctc_priv *) (dev->priv);
         
@@ -1188,6 +1319,7 @@
                         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;
@@ -1264,8 +1396,7 @@
         }
 
         printk(KERN_INFO "%s: connected with remote side\n",dev->name);
-        dev->start = 1;
-        dev->tbusy = 0;
+        ctc_clear_busy(dev);
         return 0;
 }
 
@@ -1273,9 +1404,9 @@
 static void ctc_timer (struct channel *ctc)
 {
 #ifdef DEBUG
-        struct device      *dev;
+        net_device  *dev;
 
-        dev = (struct device *) ctc->dev; 
+        dev = (net_device *) ctc->dev; 
         printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
 #endif
         ctc->flag |= CTC_TIMER;
@@ -1287,24 +1418,26 @@
  *   ctc_release 
  *
  */
-static int ctc_release(struct device *dev)
+static int ctc_release(net_device *dev)
 {   
         int                rc;
+        int                x; 
         int                i;
         int                j;
         __u8               flags = 0x00;
         __u32              saveflags;
         __u32              parm;
         struct ctc_priv    *privptr;
-        struct wait_queue  wait = { current, NULL }; 
+	DECLARE_WAITQUEUE(wait, current);
 
         privptr = (struct ctc_priv *) dev->priv;  
    
-        dev->start = 0;
-        set_bit(TB_STOP, (void *)&dev->tbusy);    
-        
+	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 );
@@ -1339,15 +1472,16 @@
  *
  *
  */
-static int ctc_tx(struct sk_buff *skb, struct device *dev)
+static int ctc_tx(struct sk_buff *skb, net_device *dev)
 {
-        int                rc;
+        int                rc=0,rc2;
         __u32              parm;
         __u8               flags = 0x00;
         __u32              saveflags;
         struct ctc_priv    *privptr;
         struct packet      *lp;
    
+   
         privptr = (struct ctc_priv *) (dev->priv);
 
         if (skb == NULL) { 
@@ -1356,25 +1490,27 @@
                 return -EIO;
         }
         
-        if (dev->tbusy != 0) {
-                return -EBUSY;
+        s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
+        if (ctc_check_busy(dev)) {
+                rc=-EBUSY;
+		goto Done;
         } 
 
-        if (test_and_set_bit(TB_TX, (void *)&dev->tbusy) != 0) {                /* set transmission to busy */
-                return -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) {
 #ifdef DEBUG
                 printk(KERN_DEBUG "%s: early swap\n", dev->name);
 #endif
-                s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
+               
                 ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor);
-                s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
                 if (privptr->channel[WRITE].free_anchor == NULL){
-                        set_bit(TB_NOBUFFER, (void *)&dev->tbusy);
-                        clear_bit(TB_TX, (void *)&dev->tbusy);
-                        return -EBUSY;
+                        ctc_setbit_busy(TB_NOBUFFER,dev);
+                        rc=-EBUSY;
+			goto Done2;
                 }
         }
         
@@ -1396,23 +1532,22 @@
         privptr->channel[WRITE].free_anchor->packets++;
 
         if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) {
-                s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
                 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];  
-                rc = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
-                if (rc != 0) 
-                        ccw_check_return_code(dev, rc);
+                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;
-                s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
         }
-
         if (privptr->channel[WRITE].free_anchor == NULL)
-                set_bit(TB_NOBUFFER, (void *)&dev->tbusy);
-
-        clear_bit(TB_TX, (void *)&dev->tbusy);
-        return 0;
+                ctc_setbit_busy(TB_NOBUFFER,dev);
+Done2:
+        ctc_clearbit_busy(TB_TX,dev);
+Done:
+	s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
+        return(rc);
 } 
 
 
@@ -1423,7 +1558,7 @@
  *                                   576 to 65527 for OS/390
  *
  */
-static int ctc_change_mtu(struct device *dev, int new_mtu)
+static int ctc_change_mtu(net_device *dev, int new_mtu)
 {
         if ((new_mtu < 576) || (new_mtu > 65528))
                 return -EINVAL;
@@ -1436,7 +1571,7 @@
  *   ctc_stats
  *
  */
-struct net_device_stats *ctc_stats(struct device *dev)
+struct net_device_stats *ctc_stats(net_device *dev)
 {
          struct ctc_priv *privptr;
    

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)