qeth: change checksumming default for HiperSockets
[cascardo/linux.git] / drivers / s390 / net / qeth_core_main.c
index d34804d..c9f5af5 100644 (file)
@@ -269,6 +269,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
        card->qdio.init_pool.buf_count = bufcnt;
        return qeth_alloc_buffer_pool(card);
 }
+EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool);
 
 static int qeth_issue_next_read(struct qeth_card *card)
 {
@@ -350,8 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
        if (IS_IPA(iob->data)) {
                cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
                if (IS_IPA_REPLY(cmd)) {
-                       if (cmd->hdr.command < IPA_CMD_SETCCID ||
-                           cmd->hdr.command > IPA_CMD_MODCCID)
+                       if (cmd->hdr.command != IPA_CMD_SETCCID &&
+                           cmd->hdr.command != IPA_CMD_DELCCID &&
+                           cmd->hdr.command != IPA_CMD_MODCCID &&
+                           cmd->hdr.command != IPA_CMD_SET_DIAG_ASS)
                                qeth_issue_ipa_msg(cmd,
                                                cmd->hdr.return_code, card);
                        return cmd;
@@ -534,7 +537,8 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
                        dev_err(&card->gdev->dev,
                                "The qeth device is not configured "
                                "for the OSI layer required by z/VM\n");
-               qeth_schedule_recovery(card);
+               else
+                       qeth_schedule_recovery(card);
                goto out;
        }
 
@@ -1100,11 +1104,6 @@ static int qeth_setup_card(struct qeth_card *card)
        card->thread_running_mask = 0;
        INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
        INIT_LIST_HEAD(&card->ip_list);
-       card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
-       if (!card->ip_tbd_list) {
-               QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
-               return -ENOMEM;
-       }
        INIT_LIST_HEAD(card->ip_tbd_list);
        INIT_LIST_HEAD(&card->cmd_waiter_list);
        init_waitqueue_head(&card->wait_q);
@@ -1115,8 +1114,6 @@ static int qeth_setup_card(struct qeth_card *card)
        card->ipato.enabled = 0;
        card->ipato.invert4 = 0;
        card->ipato.invert6 = 0;
-       if (card->info.type == QETH_CARD_TYPE_IQD)
-               card->options.checksum_type = NO_CHECKSUMMING;
        /* init QDIO stuff */
        qeth_init_qdio_info(card);
        return 0;
@@ -1138,21 +1135,30 @@ static struct qeth_card *qeth_alloc_card(void)
        QETH_DBF_TEXT(SETUP, 2, "alloccrd");
        card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL);
        if (!card)
-               return NULL;
+               goto out;
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
-       if (qeth_setup_channel(&card->read)) {
-               kfree(card);
-               return NULL;
-       }
-       if (qeth_setup_channel(&card->write)) {
-               qeth_clean_channel(&card->read);
-               kfree(card);
-               return NULL;
+       card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+       if (!card->ip_tbd_list) {
+               QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
+               goto out_card;
        }
+       if (qeth_setup_channel(&card->read))
+               goto out_ip;
+       if (qeth_setup_channel(&card->write))
+               goto out_channel;
        card->options.layer2 = -1;
        card->qeth_service_level.seq_print = qeth_core_sl_print;
        register_service_level(&card->qeth_service_level);
        return card;
+
+out_channel:
+       qeth_clean_channel(&card->read);
+out_ip:
+       kfree(card->ip_tbd_list);
+out_card:
+       kfree(card);
+out:
+       return NULL;
 }
 
 static int qeth_determine_card_type(struct qeth_card *card)
@@ -1355,26 +1361,29 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
        return ret;
 }
 
-static int qeth_get_unitaddr(struct qeth_card *card)
+static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd)
 {
-       int length;
-       char *prcd;
-       int rc;
-
-       QETH_DBF_TEXT(SETUP, 2, "getunit");
-       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
-       if (rc) {
-               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
-                       dev_name(&card->gdev->dev), rc);
-               return rc;
-       }
+       QETH_DBF_TEXT(SETUP, 2, "cfgunit");
        card->info.chpid = prcd[30];
        card->info.unit_addr2 = prcd[31];
        card->info.cula = prcd[63];
        card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
                               (prcd[0x11] == _ascebc['M']));
-       kfree(prcd);
-       return 0;
+}
+
+static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd)
+{
+       QETH_DBF_TEXT(SETUP, 2, "cfgblkt");
+
+       if (prcd[74] == 0xF0 && prcd[75] == 0xF0 && prcd[76] == 0xF5) {
+               card->info.blkt.time_total = 250;
+               card->info.blkt.inter_packet = 5;
+               card->info.blkt.inter_packet_jumbo = 15;
+       } else {
+               card->info.blkt.time_total = 0;
+               card->info.blkt.inter_packet = 0;
+               card->info.blkt.inter_packet_jumbo = 0;
+       }
 }
 
 static void qeth_init_tokens(struct qeth_card *card)
@@ -2573,8 +2582,8 @@ int qeth_query_setadapterparms(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_query_setadapterparms);
 
-int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
-               const char *dbftext)
+int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
+               unsigned int qdio_error, const char *dbftext)
 {
        if (qdio_error) {
                QETH_DBF_TEXT(TRACE, 2, dbftext);
@@ -2584,7 +2593,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
                QETH_DBF_TEXT_(QERR, 2, " F14=%02X",
                               buf->element[14].flags & 0xff);
                QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error);
-               return 1;
+               if ((buf->element[15].flags & 0xff) == 0x12) {
+                       card->stats.rx_dropped++;
+                       return 0;
+               } else
+                       return 1;
        }
        return 0;
 }
@@ -2667,7 +2680,7 @@ static int qeth_handle_send_error(struct qeth_card *card,
                        qdio_err = 1;
                }
        }
-       qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr");
+       qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr");
 
        if (!qdio_err)
                return QETH_SEND_ERROR_NONE;
@@ -3509,6 +3522,7 @@ void qeth_tx_timeout(struct net_device *dev)
 {
        struct qeth_card *card;
 
+       QETH_DBF_TEXT(TRACE, 4, "txtimeo");
        card = dev->ml_priv;
        card->stats.tx_errors++;
        qeth_schedule_recovery(card);
@@ -3847,9 +3861,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev,
 
 int qeth_core_hardsetup_card(struct qeth_card *card)
 {
-       struct qdio_ssqd_desc *ssqd;
        int retries = 0;
-       int mpno = 0;
        int rc;
 
        QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
@@ -3882,31 +3894,6 @@ retriable:
                else
                        goto retry;
        }
-
-       rc = qeth_get_unitaddr(card);
-       if (rc) {
-               QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
-               return rc;
-       }
-
-       ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL);
-       if (!ssqd) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd);
-       if (rc == 0)
-               mpno = ssqd->pcnt;
-       kfree(ssqd);
-
-       if (mpno)
-               mpno = min(mpno - 1, QETH_MAX_PORTNO);
-       if (card->info.portno > mpno) {
-               QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d"
-                       "\n.", CARD_BUS_ID(card), card->info.portno);
-               rc = -ENODEV;
-               goto out;
-       }
        qeth_init_tokens(card);
        qeth_init_func_level(card);
        rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
@@ -3990,7 +3977,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
        struct qdio_buffer_element *element = *__element;
        int offset = *__offset;
        struct sk_buff *skb = NULL;
-       int skb_len;
+       int skb_len = 0;
        void *data_ptr;
        int data_len;
        int headroom = 0;
@@ -4009,20 +3996,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
        *hdr = element->addr + offset;
 
        offset += sizeof(struct qeth_hdr);
-       if (card->options.layer2) {
-               if (card->info.type == QETH_CARD_TYPE_OSN) {
-                       skb_len = (*hdr)->hdr.osn.pdu_length;
-                       headroom = sizeof(struct qeth_hdr);
-               } else {
-                       skb_len = (*hdr)->hdr.l2.pkt_length;
-               }
-       } else {
+       switch ((*hdr)->hdr.l2.id) {
+       case QETH_HEADER_TYPE_LAYER2:
+               skb_len = (*hdr)->hdr.l2.pkt_length;
+               break;
+       case QETH_HEADER_TYPE_LAYER3:
                skb_len = (*hdr)->hdr.l3.length;
                if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
                    (card->info.link_type == QETH_LINK_TYPE_HSTR))
                        headroom = TR_HLEN;
                else
                        headroom = ETH_HLEN;
+               break;
+       case QETH_HEADER_TYPE_OSN:
+               skb_len = (*hdr)->hdr.osn.pdu_length;
+               headroom = sizeof(struct qeth_hdr);
+               break;
+       default:
+               break;
        }
 
        if (!skb_len)
@@ -4177,6 +4168,41 @@ void qeth_core_free_discipline(struct qeth_card *card)
        card->discipline.ccwgdriver = NULL;
 }
 
+static void qeth_determine_capabilities(struct qeth_card *card)
+{
+       int rc;
+       int length;
+       char *prcd;
+
+       QETH_DBF_TEXT(SETUP, 2, "detcapab");
+       rc = ccw_device_set_online(CARD_DDEV(card));
+       if (rc) {
+               QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+               goto out;
+       }
+
+
+       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
+       if (rc) {
+               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
+                       dev_name(&card->gdev->dev), rc);
+               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+               goto out_offline;
+       }
+       qeth_configure_unitaddr(card, prcd);
+       qeth_configure_blkt_default(card, prcd);
+       kfree(prcd);
+
+       rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+       if (rc)
+               QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+
+out_offline:
+       ccw_device_set_offline(CARD_DDEV(card));
+out:
+       return;
+}
+
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card;
@@ -4242,6 +4268,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
        write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
        list_add_tail(&card->list, &qeth_core_card_list.list);
        write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
+
+       qeth_determine_capabilities(card);
        return 0;
 
 err_card: