Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
[safe/jmp/linux-2.6] / drivers / s390 / net / qeth_core_main.c
index 28f7134..13ef46b 100644 (file)
@@ -53,7 +53,7 @@ struct kmem_cache *qeth_core_header_cache;
 EXPORT_SYMBOL_GPL(qeth_core_header_cache);
 
 static struct device *qeth_core_root_dev;
-static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY;
+static unsigned int known_devices[][6] = QETH_MODELLIST_ARRAY;
 static struct lock_class_key qdio_out_skb_queue_key;
 
 static void qeth_send_control_data_cb(struct qeth_channel *,
@@ -111,21 +111,29 @@ static inline const char *qeth_get_cardname(struct qeth_card *card)
 {
        if (card->info.guestlan) {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        return " Guest LAN QDIO";
                case QETH_CARD_TYPE_IQD:
                        return " Guest LAN Hiper";
+               case QETH_CARD_TYPE_OSM:
+                       return " Guest LAN QDIO - OSM";
+               case QETH_CARD_TYPE_OSX:
+                       return " Guest LAN QDIO - OSX";
                default:
                        return " unknown";
                }
        } else {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        return " OSD Express";
                case QETH_CARD_TYPE_IQD:
                        return " HiperSockets";
                case QETH_CARD_TYPE_OSN:
                        return " OSN QDIO";
+               case QETH_CARD_TYPE_OSM:
+                       return " OSM QDIO";
+               case QETH_CARD_TYPE_OSX:
+                       return " OSX QDIO";
                default:
                        return " unknown";
                }
@@ -138,16 +146,20 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
 {
        if (card->info.guestlan) {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        return "GuestLAN QDIO";
                case QETH_CARD_TYPE_IQD:
                        return "GuestLAN Hiper";
+               case QETH_CARD_TYPE_OSM:
+                       return "GuestLAN OSM";
+               case QETH_CARD_TYPE_OSX:
+                       return "GuestLAN OSX";
                default:
                        return "unknown";
                }
        } else {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        switch (card->info.link_type) {
                        case QETH_LINK_TYPE_FAST_ETH:
                                return "OSD_100";
@@ -172,6 +184,10 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
                        return "HiperSockets";
                case QETH_CARD_TYPE_OSN:
                        return "OSN";
+               case QETH_CARD_TYPE_OSM:
+                       return "OSM_1000";
+               case QETH_CARD_TYPE_OSX:
+                       return "OSX_10GIG";
                default:
                        return "unknown";
                }
@@ -419,7 +435,8 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
 
-static int qeth_check_idx_response(unsigned char *buffer)
+static int qeth_check_idx_response(struct qeth_card *card,
+       unsigned char *buffer)
 {
        if (!buffer)
                return 0;
@@ -434,6 +451,12 @@ static int qeth_check_idx_response(unsigned char *buffer)
                QETH_DBF_TEXT(TRACE, 2, "ckidxres");
                QETH_DBF_TEXT(TRACE, 2, " idxterm");
                QETH_DBF_TEXT_(TRACE, 2, "  rc%d", -EIO);
+               if (buffer[4] == 0xf6) {
+                       dev_err(&card->gdev->dev,
+                       "The qeth device is not configured "
+                       "for the OSI layer required by z/VM\n");
+                       return -EPERM;
+               }
                return -EIO;
        }
        return 0;
@@ -528,18 +551,19 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
        struct qeth_ipa_cmd *cmd;
        unsigned long flags;
        int keep_reply;
+       int rc = 0;
 
        QETH_DBF_TEXT(TRACE, 4, "sndctlcb");
 
        card = CARD_FROM_CDEV(channel->ccwdev);
-       if (qeth_check_idx_response(iob->data)) {
+       rc = qeth_check_idx_response(card, iob->data);
+       switch (rc) {
+       case 0:
+               break;
+       case -EIO:
                qeth_clear_ipacmd_list(card);
-               if (((iob->data[2] & 0xc0) == 0xc0) && iob->data[4] == 0xf6)
-                       dev_err(&card->gdev->dev,
-                               "The qeth device is not configured "
-                               "for the OSI layer required by z/VM\n");
-               else
-                       qeth_schedule_recovery(card);
+               qeth_schedule_recovery(card);
+       default:
                goto out;
        }
 
@@ -606,7 +630,7 @@ static int qeth_setup_channel(struct qeth_channel *channel)
 
        QETH_DBF_TEXT(SETUP, 2, "setupch");
        for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
-               channel->iob[cnt].data = (char *)
+               channel->iob[cnt].data =
                        kmalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
                if (channel->iob[cnt].data == NULL)
                        break;
@@ -719,7 +743,7 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
                QETH_DBF_TEXT(TRACE, 2, "CGENCHK");
                dev_warn(&cdev->dev, "The qeth device driver "
                        "failed to recover an error on the device\n");
-               QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x ",
+               QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x\n",
                        dev_name(&cdev->dev), dstat, cstat);
                print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET,
                                16, 1, irb, 64, 1);
@@ -998,9 +1022,8 @@ static void qeth_clean_channel(struct qeth_channel *channel)
                kfree(channel->iob[cnt].data);
 }
 
-static int qeth_is_1920_device(struct qeth_card *card)
+static void qeth_get_channel_path_desc(struct qeth_card *card)
 {
-       int single_queue = 0;
        struct ccw_device *ccwdev;
        struct channelPath_dsc {
                u8 flags;
@@ -1013,17 +1036,25 @@ static int qeth_is_1920_device(struct qeth_card *card)
                u8 chpp;
        } *chp_dsc;
 
-       QETH_DBF_TEXT(SETUP, 2, "chk_1920");
+       QETH_DBF_TEXT(SETUP, 2, "chp_desc");
 
        ccwdev = card->data.ccwdev;
        chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0);
        if (chp_dsc != NULL) {
                /* CHPP field bit 6 == 1 -> single queue */
-               single_queue = ((chp_dsc->chpp & 0x02) == 0x02);
+               if ((chp_dsc->chpp & 0x02) == 0x02)
+                       card->qdio.no_out_queues = 1;
+               card->info.func_level = 0x4100 + chp_dsc->desc;
                kfree(chp_dsc);
        }
-       QETH_DBF_TEXT_(SETUP, 2, "rc:%x", single_queue);
-       return single_queue;
+       if (card->qdio.no_out_queues == 1) {
+               card->qdio.default_out_queue = 0;
+               dev_info(&card->gdev->dev,
+                       "Priority Queueing not supported\n");
+       }
+       QETH_DBF_TEXT_(SETUP, 2, "nr:%x", card->qdio.no_out_queues);
+       QETH_DBF_TEXT_(SETUP, 2, "lvl:%02x", card->info.func_level);
+       return;
 }
 
 static void qeth_init_qdio_info(struct qeth_card *card)
@@ -1100,6 +1131,7 @@ static int qeth_setup_card(struct qeth_card *card)
        spin_lock_init(&card->lock);
        spin_lock_init(&card->ip_lock);
        spin_lock_init(&card->thread_mask_lock);
+       mutex_init(&card->conf_mutex);
        card->thread_start_mask = 0;
        card->thread_allowed_mask = 0;
        card->thread_running_mask = 0;
@@ -1170,18 +1202,17 @@ static int qeth_determine_card_type(struct qeth_card *card)
 
        card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
        card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
-       while (known_devices[i][4]) {
-               if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) &&
-                   (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) {
-                       card->info.type = known_devices[i][4];
-                       card->qdio.no_out_queues = known_devices[i][8];
-                       card->info.is_multicast_different = known_devices[i][9];
-                       if (qeth_is_1920_device(card)) {
-                               dev_info(&card->gdev->dev,
-                                       "Priority Queueing not supported\n");
-                               card->qdio.no_out_queues = 1;
-                               card->qdio.default_out_queue = 0;
-                       }
+       while (known_devices[i][QETH_DEV_MODEL_IND]) {
+               if ((CARD_RDEV(card)->id.dev_type ==
+                               known_devices[i][QETH_DEV_TYPE_IND]) &&
+                   (CARD_RDEV(card)->id.dev_model ==
+                               known_devices[i][QETH_DEV_MODEL_IND])) {
+                       card->info.type = known_devices[i][QETH_DEV_MODEL_IND];
+                       card->qdio.no_out_queues =
+                               known_devices[i][QETH_QUEUE_NO_IND];
+                       card->info.is_multicast_different =
+                               known_devices[i][QETH_MULTICAST_IND];
+                       qeth_get_channel_path_desc(card);
                        return 0;
                }
                i++;
@@ -1399,22 +1430,20 @@ static void qeth_init_tokens(struct qeth_card *card)
 
 static void qeth_init_func_level(struct qeth_card *card)
 {
-       if (card->ipato.enabled) {
-               if (card->info.type == QETH_CARD_TYPE_IQD)
-                               card->info.func_level =
-                                       QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT;
-               else
-                               card->info.func_level =
-                                       QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT;
-       } else {
-               if (card->info.type == QETH_CARD_TYPE_IQD)
-               /*FIXME:why do we have same values for  dis and ena for
-                 osae??? */
+       switch (card->info.type) {
+       case QETH_CARD_TYPE_IQD:
+               if (card->ipato.enabled)
                        card->info.func_level =
-                               QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT;
+                               QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT;
                else
                        card->info.func_level =
-                               QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT;
+                               QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT;
+               break;
+       case QETH_CARD_TYPE_OSD:
+               card->info.func_level = QETH_IDX_FUNC_LEVEL_OSD;
+               break;
+       default:
+               break;
        }
 }
 
@@ -1561,7 +1590,7 @@ static void qeth_idx_write_cb(struct qeth_channel *channel,
        card = CARD_FROM_CDEV(channel->ccwdev);
 
        if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
-               if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+               if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == QETH_IDX_ACT_ERR_EXCL)
                        dev_err(&card->write.ccwdev->dev,
                                "The adapter is used exclusively by another "
                                "host\n");
@@ -1597,27 +1626,35 @@ static void qeth_idx_read_cb(struct qeth_channel *channel,
        }
 
        card = CARD_FROM_CDEV(channel->ccwdev);
-       if (qeth_check_idx_response(iob->data))
+       if (qeth_check_idx_response(card, iob->data))
                        goto out;
 
        if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
-               if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+               switch (QETH_IDX_ACT_CAUSE_CODE(iob->data)) {
+               case QETH_IDX_ACT_ERR_EXCL:
                        dev_err(&card->write.ccwdev->dev,
                                "The adapter is used exclusively by another "
                                "host\n");
-               else
+                       break;
+               case QETH_IDX_ACT_ERR_AUTH:
+                       dev_err(&card->read.ccwdev->dev,
+                               "Setting the device online failed because of "
+                               "insufficient LPAR authorization\n");
+                       break;
+               default:
                        QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:"
                                " negative reply\n",
                                dev_name(&card->read.ccwdev->dev));
+               }
                goto out;
        }
 
 /**
- * temporary fix for microcode bug
- * to revert it,replace OR by AND
- */
+ *  * temporary fix for microcode bug
+ *   * to revert it,replace OR by AND
+ *    */
        if ((!QETH_IDX_NO_PORTNAME_REQUIRED(iob->data)) ||
-            (card->info.type == QETH_CARD_TYPE_OSAE))
+            (card->info.type == QETH_CARD_TYPE_OSD))
                card->info.portname_required = 1;
 
        memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
@@ -1826,7 +1863,7 @@ static inline int qeth_get_initial_mtu_for_card(struct qeth_card *card)
                return 1500;
        case QETH_CARD_TYPE_IQD:
                return card->info.max_mtu;
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
                switch (card->info.link_type) {
                case QETH_LINK_TYPE_HSTR:
                case QETH_LINK_TYPE_LANE_TR:
@@ -1834,6 +1871,9 @@ static inline int qeth_get_initial_mtu_for_card(struct qeth_card *card)
                default:
                        return 1492;
                }
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
+               return 1492;
        default:
                return 1500;
        }
@@ -1844,8 +1884,10 @@ static inline int qeth_get_max_mtu_for_card(int cardtype)
        switch (cardtype) {
 
        case QETH_CARD_TYPE_UNKNOWN:
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
        case QETH_CARD_TYPE_OSN:
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
                return 61440;
        case QETH_CARD_TYPE_IQD:
                return 57344;
@@ -1883,7 +1925,9 @@ static inline int qeth_get_mtu_outof_framesize(int framesize)
 static inline int qeth_mtu_is_valid(struct qeth_card *card, int mtu)
 {
        switch (card->info.type) {
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
                return ((mtu >= 576) && (mtu <= 61440));
        case QETH_CARD_TYPE_IQD:
                return ((mtu >= 576) &&
@@ -1934,6 +1978,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
                card->info.link_type = link_type;
        } else
                card->info.link_type = 0;
+       QETH_DBF_TEXT_(SETUP, 2, "link%d", link_type);
        QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
        return 0;
 }
@@ -1977,6 +2022,7 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
                unsigned long data)
 {
        struct qeth_cmd_buffer *iob;
+       int rc = 0;
 
        QETH_DBF_TEXT(SETUP, 2, "ulpstpcb");
 
@@ -1984,8 +2030,15 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
        memcpy(&card->token.ulp_connection_r,
               QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(iob->data),
               QETH_MPC_TOKEN_LENGTH);
+       if (!strncmp("00S", QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(iob->data),
+                    3)) {
+               QETH_DBF_TEXT(SETUP, 2, "olmlimit");
+               dev_err(&card->gdev->dev, "A connection could not be "
+                       "established because of an OLM limit\n");
+               rc = -EMLINK;
+       }
        QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
-       return 0;
+       return rc;
 }
 
 static int qeth_ulp_setup(struct qeth_card *card)
@@ -2238,7 +2291,9 @@ static void qeth_print_status_no_portname(struct qeth_card *card)
 void qeth_print_status_message(struct qeth_card *card)
 {
        switch (card->info.type) {
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
                /* VM will use a non-zero first character
                 * to indicate a HiperSockets like reporting
                 * of the level OSA sets the first character to zero
@@ -2545,9 +2600,11 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
        QETH_DBF_TEXT(TRACE, 3, "quyadpcb");
 
        cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f)
+       if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
                card->info.link_type =
                      cmd->data.setadapterparms.data.query_cmds_supp.lan_type;
+               QETH_DBF_TEXT_(SETUP, 2, "lnk %d", card->info.link_type);
+       }
        card->options.adp.supported_funcs =
                cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds;
        return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
@@ -2937,7 +2994,8 @@ EXPORT_SYMBOL_GPL(qeth_qdio_output_handler);
 int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
                        int ipv, int cast_type)
 {
-       if (!ipv && (card->info.type == QETH_CARD_TYPE_OSAE))
+       if (!ipv && (card->info.type == QETH_CARD_TYPE_OSD ||
+                    card->info.type == QETH_CARD_TYPE_OSX))
                return card->qdio.default_out_queue;
        switch (card->qdio.no_out_queues) {
        case 4:
@@ -3499,13 +3557,14 @@ int qeth_set_access_ctrl_online(struct qeth_card *card)
 
        QETH_DBF_TEXT(TRACE, 4, "setactlo");
 
-       if (card->info.type == QETH_CARD_TYPE_OSAE &&
-           qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
+       if ((card->info.type == QETH_CARD_TYPE_OSD ||
+            card->info.type == QETH_CARD_TYPE_OSX) &&
+            qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
                rc = qeth_setadpparms_set_access_ctrl(card,
                        card->options.isolation);
                if (rc) {
                        QETH_DBF_MESSAGE(3,
-                               "IPA(SET_ACCESS_CTRL,%s,%d) sent failed",
+                               "IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n",
                                card->gdev->dev.kobj.name,
                                rc);
                }
@@ -3845,9 +3904,16 @@ static void qeth_core_free_card(struct qeth_card *card)
 }
 
 static struct ccw_device_id qeth_ids[] = {
-       {CCW_DEVICE(0x1731, 0x01), .driver_info = QETH_CARD_TYPE_OSAE},
-       {CCW_DEVICE(0x1731, 0x05), .driver_info = QETH_CARD_TYPE_IQD},
-       {CCW_DEVICE(0x1731, 0x06), .driver_info = QETH_CARD_TYPE_OSN},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x01, 0x1732, 0x01),
+                                       .driver_info = QETH_CARD_TYPE_OSD},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x05, 0x1732, 0x05),
+                                       .driver_info = QETH_CARD_TYPE_IQD},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x06, 0x1732, 0x06),
+                                       .driver_info = QETH_CARD_TYPE_OSN},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x02, 0x1732, 0x03),
+                                       .driver_info = QETH_CARD_TYPE_OSM},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x02, 0x1732, 0x02),
+                                       .driver_info = QETH_CARD_TYPE_OSX},
        {},
 };
 MODULE_DEVICE_TABLE(ccw, qeth_ids);
@@ -4251,25 +4317,25 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
                goto err_card;
        }
 
-       if (card->info.type == QETH_CARD_TYPE_OSN) {
+       if (card->info.type == QETH_CARD_TYPE_OSN)
                rc = qeth_core_create_osn_attributes(dev);
-               if (rc)
-                       goto err_card;
+       else
+               rc = qeth_core_create_device_attributes(dev);
+       if (rc)
+               goto err_card;
+       switch (card->info.type) {
+       case QETH_CARD_TYPE_OSN:
+       case QETH_CARD_TYPE_OSM:
                rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
-               if (rc) {
-                       qeth_core_remove_osn_attributes(dev);
-                       goto err_card;
-               }
+               if (rc)
+                       goto err_attr;
                rc = card->discipline.ccwgdriver->probe(card->gdev);
-               if (rc) {
-                       qeth_core_free_discipline(card);
-                       qeth_core_remove_osn_attributes(dev);
-                       goto err_card;
-               }
-       } else {
-               rc = qeth_core_create_device_attributes(dev);
                if (rc)
-                       goto err_card;
+                       goto err_disc;
+       case QETH_CARD_TYPE_OSD:
+       case QETH_CARD_TYPE_OSX:
+       default:
+               break;
        }
 
        write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
@@ -4279,6 +4345,13 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
        qeth_determine_capabilities(card);
        return 0;
 
+err_disc:
+       qeth_core_free_discipline(card);
+err_attr:
+       if (card->info.type == QETH_CARD_TYPE_OSN)
+               qeth_core_remove_osn_attributes(dev);
+       else
+               qeth_core_remove_device_attributes(dev);
 err_card:
        qeth_core_free_card(card);
 err_dev: