Merge master.kernel.org:/home/rmk/linux-2.6-serial
[powerpc.git] / drivers / s390 / net / qeth_main.c
index 99cceb2..97f927c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.242 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.251 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  *
@@ -12,7 +12,7 @@
  *                       Frank Pavlic (fpavlic@de.ibm.com) and
  *                       Thomas Spatzier <tspat@de.ibm.com>
  *
- *    $Revision: 1.242 $        $Date: 2005/05/04 20:19:18 $
+ *    $Revision: 1.251 $        $Date: 2005/05/04 20:19:18 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -65,6 +65,7 @@
 #include <asm/timex.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
+#include <asm/s390_rdev.h>
 
 #include "qeth.h"
 #include "qeth_mpc.h"
@@ -72,7 +73,7 @@
 #include "qeth_eddp.h"
 #include "qeth_tso.h"
 
-#define VERSION_QETH_C "$Revision: 1.242 $"
+#define VERSION_QETH_C "$Revision: 1.251 $"
 static const char *version = "qeth S/390 OSA-Express driver";
 
 /**
@@ -518,7 +519,8 @@ __qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
 
        QETH_DBF_TEXT(setup, 3, "setoffl");
        QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
-
+       
+       netif_carrier_off(card->dev);
        recover_flag = card->state;
        if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
                PRINT_WARN("Stopping card %s interrupted by user!\n",
@@ -1020,7 +1022,6 @@ void
 qeth_schedule_recovery(struct qeth_card *card)
 {
        QETH_DBF_TEXT(trace,2,"startrec");
-
        if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0)
                schedule_work(&card->kernel_thread_starter);
 }
@@ -1396,7 +1397,7 @@ qeth_idx_activate_get_answer(struct qeth_channel *channel,
        channel->ccw.cda = (__u32) __pa(iob->data);
 
        wait_event(card->wait_q,
-                  atomic_compare_and_swap(0,1,&channel->irq_pending) == 0);
+                  atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(setup, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
        rc = ccw_device_start(channel->ccwdev,
@@ -1463,7 +1464,7 @@ qeth_idx_activate_channel(struct qeth_channel *channel,
        memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2);
 
        wait_event(card->wait_q,
-                  atomic_compare_and_swap(0,1,&channel->irq_pending) == 0);
+                  atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(setup, 6, "noirqpnd");
        spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
        rc = ccw_device_start(channel->ccwdev,
@@ -1616,7 +1617,7 @@ qeth_issue_next_read(struct qeth_card *card)
        }
        qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
        wait_event(card->wait_q,
-                  atomic_compare_and_swap(0,1,&card->read.irq_pending) == 0);
+                  atomic_cmpxchg(&card->read.irq_pending, 0, 1) == 0);
        QETH_DBF_TEXT(trace, 6, "noirqpnd");
        rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
                              (addr_t) iob, 0, 0);
@@ -1710,7 +1711,6 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
                                           "IP address reset.\n",
                                           QETH_CARD_IFNAME(card),
                                           card->info.chpid);
-                               netif_carrier_on(card->dev);
                                qeth_schedule_recovery(card);
                                return NULL;
                        case IPA_CMD_MODCCID:
@@ -1883,7 +1883,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
        spin_unlock_irqrestore(&card->lock, flags);
        QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);
        wait_event(card->wait_q,
-                  atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0);
+                  atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
        qeth_prepare_control_data(card, len, iob);
        if (IS_IPA(iob->data))
                timer.expires = jiffies + QETH_IPA_TIMEOUT;
@@ -1925,7 +1925,7 @@ qeth_osn_send_control_data(struct qeth_card *card, int len,
        QETH_DBF_TEXT(trace, 5, "osndctrd");
 
        wait_event(card->wait_q,
-                  atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0);
+                  atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
        qeth_prepare_control_data(card, len, iob);
        QETH_DBF_TEXT(trace, 6, "osnoirqp");
        spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
@@ -1959,7 +1959,7 @@ qeth_osn_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
 {
        u16 s1, s2;
 
-QETH_DBF_TEXT(trace,4,"osndipa");
+       QETH_DBF_TEXT(trace,4,"osndipa");
 
        qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2);
        s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len);
@@ -2203,24 +2203,21 @@ qeth_ulp_setup(struct qeth_card *card)
 }
 
 static inline int
-qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf,
-                            unsigned int qdio_error,
-                            unsigned int siga_error)
+qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
+                      unsigned int siga_error, const char *dbftext)
 {
-       int rc = 0;
-
        if (qdio_error || siga_error) {
-               QETH_DBF_TEXT(trace, 2, "qdinerr");
-               QETH_DBF_TEXT(qerr, 2, "qdinerr");
+               QETH_DBF_TEXT(trace, 2, dbftext);
+               QETH_DBF_TEXT(qerr, 2, dbftext);
                QETH_DBF_TEXT_(qerr, 2, " F15=%02X",
-                              buf->buffer->element[15].flags & 0xff);
+                              buf->element[15].flags & 0xff);
                QETH_DBF_TEXT_(qerr, 2, " F14=%02X",
-                              buf->buffer->element[14].flags & 0xff);
+                              buf->element[14].flags & 0xff);
                QETH_DBF_TEXT_(qerr, 2, " qerr=%X", qdio_error);
                QETH_DBF_TEXT_(qerr, 2, " serr=%X", siga_error);
-               rc = 1;
+               return 1;
        }
-       return rc;
+       return 0;
 }
 
 static inline struct sk_buff *
@@ -2769,8 +2766,9 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
        for (i = first_element; i < (first_element + count); ++i) {
                index = i % QDIO_MAX_BUFFERS_PER_Q;
                buffer = &card->qdio.in_q->bufs[index];
-               if (!((status == QDIO_STATUS_LOOK_FOR_ERROR) &&
-                     qeth_check_for_inbound_error(buffer, qdio_err, siga_err)))
+               if (!((status & QDIO_STATUS_LOOK_FOR_ERROR) &&
+                     qeth_check_qdio_errors(buffer->buffer, 
+                                            qdio_err, siga_err,"qinerr")))
                        qeth_process_inbound_buffer(card, buffer, index);
                /* clear buffer and give back to hardware */
                qeth_put_buffer_pool_entry(card, buffer->pool_entry);
@@ -2785,12 +2783,13 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
 static inline int
 qeth_handle_send_error(struct qeth_card *card,
                       struct qeth_qdio_out_buffer *buffer,
-                      int qdio_err, int siga_err)
+                      unsigned int qdio_err, unsigned int siga_err)
 {
        int sbalf15 = buffer->buffer->element[15].flags & 0xff;
        int cc = siga_err & 3;
 
        QETH_DBF_TEXT(trace, 6, "hdsnderr");
+       qeth_check_qdio_errors(buffer->buffer, qdio_err, siga_err, "qouterr");
        switch (cc) {
        case 0:
                if (qdio_err){
@@ -3047,7 +3046,8 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
        for(i = first_element; i < (first_element + count); ++i){
                buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
                /*we only handle the KICK_IT error by doing a recovery */
-               if (qeth_handle_send_error(card, buffer, qdio_error, siga_error)
+               if (qeth_handle_send_error(card, buffer,
+                                          qdio_error, siga_error)
                                == QETH_SEND_ERROR_KICK_IT){
                        netif_stop_queue(card->dev);
                        qeth_schedule_recovery(card);
@@ -3289,7 +3289,6 @@ qeth_init_qdio_info(struct qeth_card *card)
        card->qdio.in_buf_pool.buf_count = card->qdio.init_pool.buf_count;
        INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list);
        INIT_LIST_HEAD(&card->qdio.init_pool.entry_list);
-       /* outbound */
 }
 
 static int
@@ -3731,6 +3730,9 @@ qeth_verify_vlan_dev(struct net_device *dev, struct qeth_card *card)
                        break;
                }
        }
+       if (rc && !(VLAN_DEV_INFO(dev)->real_dev->priv == (void *)card))
+               return 0;
+
 #endif
        return rc;
 }
@@ -3807,10 +3809,8 @@ qeth_open(struct net_device *dev)
        card->data.state = CH_STATE_UP;
        card->state = CARD_STATE_UP;
 
-       if (!card->lan_online){
-               if (netif_carrier_ok(dev))
-                       netif_carrier_off(dev);
-       }
+       if (!card->lan_online && netif_carrier_ok(dev))
+               netif_carrier_off(dev);
        return 0;
 }
 
@@ -4237,9 +4237,8 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
        QETH_DBF_TEXT(trace, 6, "dosndpfa");
 
        /* spin until we get the queue ... */
-       while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
-                                      QETH_OUT_Q_LOCKED,
-                                      &queue->state));
+       while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
+                             QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
        /* ... now we've got the queue */
        index = queue->next_buf_to_fill;
        buffer = &queue->bufs[queue->next_buf_to_fill];
@@ -4293,9 +4292,8 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
        QETH_DBF_TEXT(trace, 6, "dosndpkt");
 
        /* spin until we get the queue ... */
-       while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
-                                      QETH_OUT_Q_LOCKED,
-                                      &queue->state));
+       while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
+                             QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
        start_index = queue->next_buf_to_fill;
        buffer = &queue->bufs[queue->next_buf_to_fill];
        /*
@@ -5870,10 +5868,8 @@ qeth_add_multicast_ipv6(struct qeth_card *card)
        struct inet6_dev *in6_dev;
 
        QETH_DBF_TEXT(trace,4,"chkmcv6");
-       if ((card->options.layer2 == 0) &&
-           (!qeth_is_supported(card, IPA_IPV6)) )
+       if (!qeth_is_supported(card, IPA_IPV6)) 
                return ;
-
        in6_dev = in6_dev_get(card->dev);
        if (in6_dev == NULL)
                return;
@@ -7936,8 +7932,8 @@ __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                QETH_DBF_TEXT_(setup, 2, "6err%d", rc);
                goto out_remove;
        }
-/*maybe it was set offline without ifconfig down
- * we can also use this state for recovery purposes*/
+       netif_carrier_on(card->dev);
+
        qeth_set_allowed_threads(card, 0xffffffff, 0);
        if (recover_flag == CARD_STATE_RECOVER)
                qeth_start_again(card, recovery_mode);