diff options
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
| -rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 1026 | 
1 files changed, 496 insertions, 530 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index a1abb37db00..14e0b5810e8 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1,6 +1,4 @@  /* - *  drivers/s390/net/qeth_l3_main.c - *   *    Copyright IBM Corp. 2007, 2009   *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,   *		 Frank Pavlic <fpavlic@de.ibm.com>, @@ -13,6 +11,7 @@  #include <linux/module.h>  #include <linux/moduleparam.h> +#include <linux/bitops.h>  #include <linux/string.h>  #include <linux/errno.h>  #include <linux/kernel.h> @@ -23,13 +22,18 @@  #include <linux/inetdevice.h>  #include <linux/igmp.h>  #include <linux/slab.h> +#include <linux/if_vlan.h>  #include <net/ip.h>  #include <net/arp.h> +#include <net/route.h> +#include <net/ip6_fib.h>  #include <net/ip6_checksum.h> +#include <net/iucv/af_iucv.h>  #include "qeth_l3.h" +  static int qeth_l3_set_offline(struct ccwgroup_device *);  static int qeth_l3_recover(void *);  static int qeth_l3_stop(struct net_device *); @@ -42,33 +46,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *,  static int __qeth_l3_set_online(struct ccwgroup_device *, int);  static int __qeth_l3_set_offline(struct ccwgroup_device *, int); -int qeth_l3_set_large_send(struct qeth_card *card, -		enum qeth_large_send_types type) -{ -	int rc = 0; - -	card->options.large_send = type; -	if (card->dev == NULL) -		return 0; - -	if (card->options.large_send == QETH_LARGE_SEND_TSO) { -		if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { -			card->dev->features |= NETIF_F_TSO | NETIF_F_SG | -					NETIF_F_IP_CSUM; -		} else { -			card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | -					NETIF_F_IP_CSUM); -			card->options.large_send = QETH_LARGE_SEND_NO; -			rc = -EOPNOTSUPP; -		} -	} else { -		card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | -					NETIF_F_IP_CSUM); -		card->options.large_send = QETH_LARGE_SEND_NO; -	} -	return rc; -} -  static int qeth_l3_isxdigit(char *buf)  {  	while (*buf) { @@ -86,7 +63,7 @@ void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf)  int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)  {  	int count = 0, rc = 0; -	int in[4]; +	unsigned int in[4];  	char c;  	rc = sscanf(buf, "%u.%u.%u.%u%c", @@ -291,7 +268,7 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card,  	}  } -static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr) +int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)  {  	unsigned long flags;  	int rc = 0; @@ -310,7 +287,7 @@ static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)  	return rc;  } -static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) +int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)  {  	unsigned long flags;  	int rc = 0; @@ -329,7 +306,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)  } -static struct qeth_ipaddr *qeth_l3_get_addr_buffer( +struct qeth_ipaddr *qeth_l3_get_addr_buffer(  				enum qeth_prot_versions prot)  {  	struct qeth_ipaddr *addr; @@ -445,7 +422,7 @@ again:  	list_splice(&fail_list, &card->ip_list);  } -static void qeth_l3_set_ip_addr_list(struct qeth_card *card) +void qeth_l3_set_ip_addr_list(struct qeth_card *card)  {  	struct list_head *tbd_list;  	struct qeth_ipaddr *todo, *addr; @@ -455,11 +432,14 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)  	QETH_CARD_TEXT(card, 2, "sdiplist");  	QETH_CARD_HEX(card, 2, &card, sizeof(void *)); -	if (card->options.sniffer) +	if ((card->state != CARD_STATE_UP && +	     card->state != CARD_STATE_SOFTSETUP) || card->options.sniffer) {  		return; +	} +  	spin_lock_irqsave(&card->ip_lock, flags);  	tbd_list = card->ip_tbd_list; -	card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); +	card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_ATOMIC);  	if (!card->ip_tbd_list) {  		QETH_CARD_TEXT(card, 0, "silnomem");  		card->ip_tbd_list = tbd_list; @@ -506,8 +486,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card)  	kfree(tbd_list);  } -static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean, -					int recover) +static void qeth_l3_clear_ip_list(struct qeth_card *card, int recover)  {  	struct qeth_ipaddr *addr, *tmp;  	unsigned long flags; @@ -526,11 +505,6 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean,  		addr = list_entry(card->ip_list.next,  				  struct qeth_ipaddr, entry);  		list_del_init(&addr->entry); -		if (clean) { -			spin_unlock_irqrestore(&card->ip_lock, flags); -			qeth_l3_deregister_addr_entry(card, addr); -			spin_lock_irqsave(&card->ip_lock, flags); -		}  		if (!recover || addr->is_multicast) {  			kfree(addr);  			continue; @@ -649,7 +623,7 @@ static int qeth_l3_send_setrouting(struct qeth_card *card,  	return rc;  } -static void qeth_l3_correct_routing_type(struct qeth_card *card, +static int qeth_l3_correct_routing_type(struct qeth_card *card,  		enum qeth_routing_types *type, enum qeth_prot_versions prot)  {  	if (card->info.type == QETH_CARD_TYPE_IQD) { @@ -658,7 +632,7 @@ static void qeth_l3_correct_routing_type(struct qeth_card *card,  		case PRIMARY_CONNECTOR:  		case SECONDARY_CONNECTOR:  		case MULTICAST_ROUTER: -			return; +			return 0;  		default:  			goto out_inval;  		} @@ -667,17 +641,18 @@ static void qeth_l3_correct_routing_type(struct qeth_card *card,  		case NO_ROUTER:  		case PRIMARY_ROUTER:  		case SECONDARY_ROUTER: -			return; +			return 0;  		case MULTICAST_ROUTER:  			if (qeth_is_ipafunc_supported(card, prot,  						      IPA_OSA_MC_ROUTER)) -				return; +				return 0;  		default:  			goto out_inval;  		}  	}  out_inval:  	*type = NO_ROUTER; +	return -EINVAL;  }  int qeth_l3_setrouting_v4(struct qeth_card *card) @@ -686,8 +661,10 @@ int qeth_l3_setrouting_v4(struct qeth_card *card)  	QETH_CARD_TEXT(card, 3, "setrtg4"); -	qeth_l3_correct_routing_type(card, &card->options.route4.type, +	rc = qeth_l3_correct_routing_type(card, &card->options.route4.type,  				  QETH_PROT_IPV4); +	if (rc) +		return rc;  	rc = qeth_l3_send_setrouting(card, card->options.route4.type,  				  QETH_PROT_IPV4); @@ -709,8 +686,10 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)  	if (!qeth_is_supported(card, IPA_IPV6))  		return 0; -	qeth_l3_correct_routing_type(card, &card->options.route6.type, +	rc = qeth_l3_correct_routing_type(card, &card->options.route6.type,  				  QETH_PROT_IPV6); +	if (rc) +		return rc;  	rc = qeth_l3_send_setrouting(card, card->options.route6.type,  				  QETH_PROT_IPV6); @@ -820,6 +799,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,  		rc = -EEXIST;  	spin_unlock_irqrestore(&card->ip_lock, flags);  	if (rc) { +		kfree(ipaddr);  		return rc;  	}  	if (!qeth_l3_add_ip(card, ipaddr)) @@ -884,6 +864,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,  		rc = -EEXIST;  	spin_unlock_irqrestore(&card->ip_lock, flags);  	if (rc) { +		kfree(ipaddr);  		return rc;  	}  	if (!qeth_l3_add_ip(card, ipaddr)) @@ -1000,57 +981,6 @@ static inline u8 qeth_l3_get_qeth_hdr_flags6(int cast_type)  	return ct | QETH_CAST_UNICAST;  } -static int qeth_l3_send_setadp_mode(struct qeth_card *card, __u32 command, -					__u32 mode) -{ -	int rc; -	struct qeth_cmd_buffer *iob; -	struct qeth_ipa_cmd *cmd; - -	QETH_CARD_TEXT(card, 4, "adpmode"); - -	iob = qeth_get_adapter_cmd(card, command, -				   sizeof(struct qeth_ipacmd_setadpparms)); -	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); -	cmd->data.setadapterparms.data.mode = mode; -	rc = qeth_send_ipa_cmd(card, iob, qeth_default_setadapterparms_cb, -			       NULL); -	return rc; -} - -static int qeth_l3_setadapter_hstr(struct qeth_card *card) -{ -	int rc; - -	QETH_CARD_TEXT(card, 4, "adphstr"); - -	if (qeth_adp_supported(card, IPA_SETADP_SET_BROADCAST_MODE)) { -		rc = qeth_l3_send_setadp_mode(card, -					IPA_SETADP_SET_BROADCAST_MODE, -					card->options.broadcast_mode); -		if (rc) -			QETH_DBF_MESSAGE(2, "couldn't set broadcast mode on " -				   "device %s: x%x\n", -				   CARD_BUS_ID(card), rc); -		rc = qeth_l3_send_setadp_mode(card, -					IPA_SETADP_ALTER_MAC_ADDRESS, -					card->options.macaddr_mode); -		if (rc) -			QETH_DBF_MESSAGE(2, "couldn't set macaddr mode on " -				   "device %s: x%x\n", CARD_BUS_ID(card), rc); -		return rc; -	} -	if (card->options.broadcast_mode == QETH_TR_BROADCAST_LOCAL) -		QETH_DBF_MESSAGE(2, "set adapter parameters not available " -			   "to set broadcast mode, using ALLRINGS " -			   "on device %s:\n", CARD_BUS_ID(card)); -	if (card->options.macaddr_mode == QETH_TR_MACADDR_CANONICAL) -		QETH_DBF_MESSAGE(2, "set adapter parameters not available " -			   "to set macaddr mode, using NONCANONICAL " -			   "on device %s:\n", CARD_BUS_ID(card)); -	return 0; -} -  static int qeth_l3_setadapter_parms(struct qeth_card *card)  {  	int rc; @@ -1076,10 +1006,6 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card)  				" address failed\n");  	} -	if ((card->info.link_type == QETH_LINK_TYPE_HSTR) || -	    (card->info.link_type == QETH_LINK_TYPE_LANE_TR)) -		rc = qeth_l3_setadapter_hstr(card); -  	return rc;  } @@ -1306,39 +1232,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card)  	return rc;  } -static int qeth_l3_query_ipassists_cb(struct qeth_card *card, -		struct qeth_reply *reply, unsigned long data) -{ -	struct qeth_ipa_cmd *cmd; - -	QETH_DBF_TEXT(SETUP, 2, "qipasscb"); - -	cmd = (struct qeth_ipa_cmd *) data; -	if (cmd->hdr.prot_version == QETH_PROT_IPV4) { -		card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported; -		card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; -	} else { -		card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported; -		card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; -	} -	QETH_DBF_TEXT(SETUP, 2, "suppenbl"); -	QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported); -	QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled); -	return 0; -} - -static int qeth_l3_query_ipassists(struct qeth_card *card, -				enum qeth_prot_versions prot) -{ -	int rc; -	struct qeth_cmd_buffer *iob; - -	QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot); -	iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot); -	rc = qeth_send_ipa_cmd(card, iob, qeth_l3_query_ipassists_cb, NULL); -	return rc; -} -  #ifdef CONFIG_QETH_IPV6  static int qeth_l3_softsetup_ipv6(struct qeth_card *card)  { @@ -1349,7 +1242,7 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)  	if (card->info.type == QETH_CARD_TYPE_IQD)  		goto out; -	rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6); +	rc = qeth_query_ipassists(card, QETH_PROT_IPV6);  	if (rc) {  		dev_err(&card->gdev->dev,  			"Activating IPv6 support for %s failed\n", @@ -1474,68 +1367,38 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card)  	return 0;  } -int qeth_l3_set_rx_csum(struct qeth_card *card, -	enum qeth_checksum_types csum_type) +static int qeth_l3_set_rx_csum(struct qeth_card *card, int on)  {  	int rc = 0; -	if (card->options.checksum_type == HW_CHECKSUMMING) { -		if ((csum_type != HW_CHECKSUMMING) && -			(card->state != CARD_STATE_DOWN)) { -			rc = qeth_l3_send_simple_setassparms(card, -				IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); -			if (rc) -				return -EIO; -		} +	if (on) { +		rc = qeth_l3_send_checksum_command(card); +		if (rc) +			return -EIO; +		dev_info(&card->gdev->dev, +			"HW Checksumming (inbound) enabled\n");  	} else { -		if (csum_type == HW_CHECKSUMMING) { -			if (card->state != CARD_STATE_DOWN) { -				if (!qeth_is_supported(card, -				    IPA_INBOUND_CHECKSUM)) -					return -EPERM; -				rc = qeth_l3_send_checksum_command(card); -				if (rc) -					return -EIO; -			} -		} +		rc = qeth_l3_send_simple_setassparms(card, +			IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); +		if (rc) +			return -EIO;  	} -	card->options.checksum_type = csum_type; -	return rc; + +	return 0;  }  static int qeth_l3_start_ipa_checksum(struct qeth_card *card)  { -	int rc = 0; -  	QETH_CARD_TEXT(card, 3, "strtcsum"); -	if (card->options.checksum_type == NO_CHECKSUMMING) { -		dev_info(&card->gdev->dev, -			"Using no checksumming on %s.\n", -			QETH_CARD_IFNAME(card)); -		return 0; -	} -	if (card->options.checksum_type == SW_CHECKSUMMING) { -		dev_info(&card->gdev->dev, -			"Using SW checksumming on %s.\n", -			QETH_CARD_IFNAME(card)); -		return 0; -	} -	if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { -		dev_info(&card->gdev->dev, -			"Inbound HW Checksumming not " -			"supported on %s,\ncontinuing " -			"using Inbound SW Checksumming\n", -			QETH_CARD_IFNAME(card)); -		card->options.checksum_type = SW_CHECKSUMMING; -		return 0; +	if (card->dev->features & NETIF_F_RXCSUM) { +		rtnl_lock(); +		/* force set_features call */ +		card->dev->features &= ~NETIF_F_RXCSUM; +		netdev_update_features(card->dev); +		rtnl_unlock();  	} -	rc = qeth_l3_send_checksum_command(card); -	if (!rc) -		dev_info(&card->gdev->dev, -			"HW Checksumming (inbound) enabled\n"); - -	return rc; +	return 0;  }  static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card) @@ -1582,10 +1445,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card)  			dev_info(&card->gdev->dev,  				"Outbound TSO enabled\n");  	} -	if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) { -		card->options.large_send = QETH_LARGE_SEND_NO; -		card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); -	} +	if (rc) +		card->dev->features &= ~NETIF_F_TSO;  	return rc;  } @@ -1593,7 +1454,8 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)  {  	QETH_CARD_TEXT(card, 3, "strtipas"); -	qeth_set_access_ctrl_online(card);	/* go on*/ +	if (qeth_set_access_ctrl_online(card, 0)) +		return -EIO;  	qeth_l3_start_ipa_arp_processing(card);	/* go on*/  	qeth_l3_start_ipa_ip_fragmentation(card);	/* go on*/  	qeth_l3_start_ipa_source_mac(card);	/* go on*/ @@ -1607,29 +1469,6 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)  	return 0;  } -static int qeth_l3_put_unique_id(struct qeth_card *card) -{ - -	int rc = 0; -	struct qeth_cmd_buffer *iob; -	struct qeth_ipa_cmd *cmd; - -	QETH_CARD_TEXT(card, 2, "puniqeid"); - -	if ((card->info.unique_id & UNIQUE_ID_NOT_BY_CARD) == -		UNIQUE_ID_NOT_BY_CARD) -		return -1; -	iob = qeth_get_ipacmd_buffer(card, IPA_CMD_DESTROY_ADDR, -				     QETH_PROT_IPV6); -	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); -	*((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) = -				card->info.unique_id; -	memcpy(&cmd->data.create_destroy_addr.unique_id[0], -	       card->dev->dev_addr, OSA_ADDR_LEN); -	rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); -	return rc; -} -  static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,  		struct qeth_reply *reply, unsigned long data)  { @@ -1640,7 +1479,7 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,  		memcpy(card->dev->dev_addr,  			cmd->data.create_destroy_addr.unique_id, ETH_ALEN);  	else -		random_ether_addr(card->dev->dev_addr); +		eth_random_addr(card->dev->dev_addr);  	return 0;  } @@ -1783,10 +1622,7 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)  static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac,  				struct net_device *dev)  { -	if (dev->type == ARPHRD_IEEE802_TR) -		ip_tr_mc_map(ipm, mac); -	else -		ip_eth_mc_map(ipm, mac); +	ip_eth_mc_map(ipm, mac);  }  static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev) @@ -1810,29 +1646,28 @@ static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev)  	}  } +/* called with rcu_read_lock */  static void qeth_l3_add_vlan_mc(struct qeth_card *card)  {  	struct in_device *in_dev; -	struct vlan_group *vg; -	int i; +	u16 vid;  	QETH_CARD_TEXT(card, 4, "addmcvl"); -	if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL)) +	if (!qeth_is_supported(card, IPA_FULL_VLAN))  		return; -	vg = card->vlangrp; -	for (i = 0; i < VLAN_N_VID; i++) { -		struct net_device *netdev = vlan_group_get_device(vg, i); +	for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) { +		struct net_device *netdev; + +		netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q), +					      vid);  		if (netdev == NULL ||  		    !(netdev->flags & IFF_UP))  			continue; -		in_dev = in_dev_get(netdev); +		in_dev = __in_dev_get_rcu(netdev);  		if (!in_dev)  			continue; -		rcu_read_lock();  		qeth_l3_add_mc(card, in_dev); -		rcu_read_unlock(); -		in_dev_put(in_dev);  	}  } @@ -1841,14 +1676,14 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)  	struct in_device *in4_dev;  	QETH_CARD_TEXT(card, 4, "chkmcv4"); -	in4_dev = in_dev_get(card->dev); -	if (in4_dev == NULL) -		return;  	rcu_read_lock(); +	in4_dev = __in_dev_get_rcu(card->dev); +	if (in4_dev == NULL) +		goto unlock;  	qeth_l3_add_mc(card, in4_dev);  	qeth_l3_add_vlan_mc(card); +unlock:  	rcu_read_unlock(); -	in_dev_put(in4_dev);  }  #ifdef CONFIG_QETH_IPV6 @@ -1873,19 +1708,21 @@ static void qeth_l3_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)  	}  } +/* called with rcu_read_lock */  static void qeth_l3_add_vlan_mc6(struct qeth_card *card)  {  	struct inet6_dev *in_dev; -	struct vlan_group *vg; -	int i; +	u16 vid;  	QETH_CARD_TEXT(card, 4, "admc6vl"); -	if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL)) +	if (!qeth_is_supported(card, IPA_FULL_VLAN))  		return; -	vg = card->vlangrp; -	for (i = 0; i < VLAN_N_VID; i++) { -		struct net_device *netdev = vlan_group_get_device(vg, i); +	for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) { +		struct net_device *netdev; + +		netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q), +					      vid);  		if (netdev == NULL ||  		    !(netdev->flags & IFF_UP))  			continue; @@ -1909,10 +1746,12 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)  	in6_dev = in6_dev_get(card->dev);  	if (in6_dev == NULL)  		return; +	rcu_read_lock();  	read_lock_bh(&in6_dev->lock);  	qeth_l3_add_mc6(card, in6_dev);  	qeth_l3_add_vlan_mc6(card);  	read_unlock_bh(&in6_dev->lock); +	rcu_read_unlock();  	in6_dev_put(in6_dev);  }  #endif /* CONFIG_QETH_IPV6 */ @@ -1923,10 +1762,14 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,  	struct in_device *in_dev;  	struct in_ifaddr *ifa;  	struct qeth_ipaddr *addr; +	struct net_device *netdev;  	QETH_CARD_TEXT(card, 4, "frvaddr4"); -	in_dev = in_dev_get(vlan_group_get_device(card->vlangrp, vid)); +	netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q), vid); +	if (!netdev) +		return; +	in_dev = in_dev_get(netdev);  	if (!in_dev)  		return;  	for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { @@ -1949,10 +1792,14 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,  	struct inet6_dev *in6_dev;  	struct inet6_ifaddr *ifa;  	struct qeth_ipaddr *addr; +	struct net_device *netdev;  	QETH_CARD_TEXT(card, 4, "frvaddr6"); -	in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid)); +	netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q), vid); +	if (!netdev) +		return; +	in6_dev = in6_dev_get(netdev);  	if (!in6_dev)  		return;  	list_for_each_entry(ifa, &in6_dev->addr_list, if_list) { @@ -1973,30 +1820,23 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,  static void qeth_l3_free_vlan_addresses(struct qeth_card *card,  			unsigned short vid)  { -	if (!card->vlangrp) -		return; +	rcu_read_lock();  	qeth_l3_free_vlan_addresses4(card, vid);  	qeth_l3_free_vlan_addresses6(card, vid); +	rcu_read_unlock();  } -static void qeth_l3_vlan_rx_register(struct net_device *dev, -			struct vlan_group *grp) +static int qeth_l3_vlan_rx_add_vid(struct net_device *dev, +				   __be16 proto, u16 vid)  {  	struct qeth_card *card = dev->ml_priv; -	unsigned long flags; - -	QETH_CARD_TEXT(card, 4, "vlanreg"); -	spin_lock_irqsave(&card->vlanlock, flags); -	card->vlangrp = grp; -	spin_unlock_irqrestore(&card->vlanlock, flags); -} -static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) -{ -	return; +	set_bit(vid, card->active_vlans); +	return 0;  } -static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev, +				    __be16 proto, u16 vid)  {  	struct qeth_card *card = dev->ml_priv;  	unsigned long flags; @@ -2004,14 +1844,15 @@ static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)  	QETH_CARD_TEXT_(card, 4, "kid:%d", vid);  	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {  		QETH_CARD_TEXT(card, 3, "kidREC"); -		return; +		return 0;  	}  	spin_lock_irqsave(&card->vlanlock, flags);  	/* unregister IP addresses of vlan device */  	qeth_l3_free_vlan_addresses(card, vid); -	vlan_group_set_device(card->vlangrp, vid, NULL); +	clear_bit(vid, card->active_vlans);  	spin_unlock_irqrestore(&card->vlanlock, flags);  	qeth_l3_set_multicast_list(card->dev); +	return 0;  }  static inline int qeth_l3_rebuild_skb(struct qeth_card *card, @@ -2038,8 +1879,6 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card,  #endif  			case __constant_htons(ETH_P_IP):  				ip_hdr = (struct iphdr *)skb->data; -				(card->dev->type == ARPHRD_IEEE802_TR) ? -				ip_tr_mc_map(ip_hdr->daddr, tg_addr):  				ip_eth_mc_map(ip_hdr->daddr, tg_addr);  				break;  			default: @@ -2075,12 +1914,7 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card,  				tg_addr, "FAKELL", card->dev->addr_len);  	} -#ifdef CONFIG_TR -	if (card->dev->type == ARPHRD_IEEE802_TR) -		skb->protocol = tr_type_trans(skb, card->dev); -	else -#endif -		skb->protocol = eth_type_trans(skb, card->dev); +	skb->protocol = eth_type_trans(skb, card->dev);  	if (hdr->hdr.l3.ext_flags &  	    (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) { @@ -2089,14 +1923,7 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card,  		is_vlan = 1;  	} -	switch (card->options.checksum_type) { -	case SW_CHECKSUMMING: -		skb->ip_summed = CHECKSUM_NONE; -		break; -	case NO_CHECKSUMMING: -		skb->ip_summed = CHECKSUM_UNNECESSARY; -		break; -	case HW_CHECKSUMMING: +	if (card->dev->features & NETIF_F_RXCSUM) {  		if ((hdr->hdr.l3.ext_flags &  		    (QETH_HDR_EXT_CSUM_HDR_REQ |  		     QETH_HDR_EXT_CSUM_TRANSP_REQ)) == @@ -2105,7 +1932,8 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card,  			skb->ip_summed = CHECKSUM_UNNECESSARY;  		else  			skb->ip_summed = CHECKSUM_NONE; -	} +	} else +		skb->ip_summed = CHECKSUM_NONE;  	return is_vlan;  } @@ -2119,12 +1947,13 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,  	__u16 vlan_tag = 0;  	int is_vlan;  	unsigned int len; +	__u16 magic;  	*done = 0; -	BUG_ON(!budget); +	WARN_ON_ONCE(!budget);  	while (budget) {  		skb = qeth_core_get_next_skb(card, -			card->qdio.in_q->bufs[card->rx.b_index].buffer, +			&card->qdio.in_q->bufs[card->rx.b_index],  			&card->rx.b_element, &card->rx.e_offset, &hdr);  		if (!skb) {  			*done = 1; @@ -2133,14 +1962,27 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,  		skb->dev = card->dev;  		switch (hdr->hdr.l3.id) {  		case QETH_HEADER_TYPE_LAYER3: -			is_vlan = qeth_l3_rebuild_skb(card, skb, hdr, +			magic = *(__u16 *)skb->data; +			if ((card->info.type == QETH_CARD_TYPE_IQD) && +			    (magic == ETH_P_AF_IUCV)) { +				skb->protocol = ETH_P_AF_IUCV; +				skb->pkt_type = PACKET_HOST; +				skb->mac_header = NET_SKB_PAD; +				skb->dev = card->dev; +				len = skb->len; +				card->dev->header_ops->create(skb, card->dev, 0, +					card->dev->dev_addr, "FAKELL", +					card->dev->addr_len); +				netif_receive_skb(skb); +			} else { +				is_vlan = qeth_l3_rebuild_skb(card, skb, hdr,  						      &vlan_tag); -			len = skb->len; -			if (is_vlan && !card->options.sniffer) -				vlan_gro_receive(&card->napi, card->vlangrp, -					vlan_tag, skb); -			else +				len = skb->len; +				if (is_vlan && !card->options.sniffer) +					__vlan_hwaccel_put_tag(skb, +						htons(ETH_P_8021Q), vlan_tag);  				napi_gro_receive(&card->napi, skb); +			}  			break;  		case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */  			skb->pkt_type = PACKET_HOST; @@ -2241,15 +2083,16 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev,  			struct qeth_card *card)  {  	int rc = 0; -	struct vlan_group *vg; -	int i; +	u16 vid; -	vg = card->vlangrp; -	if (!vg) -		return rc; +	for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) { +		struct net_device *netdev; -	for (i = 0; i < VLAN_N_VID; i++) { -		if (vlan_group_get_device(vg, i) == dev) { +		rcu_read_lock(); +		netdev = __vlan_find_dev_deep_rcu(card->dev, htons(ETH_P_8021Q), +					      vid); +		rcu_read_unlock(); +		if (netdev == dev) {  			rc = QETH_VLAN_CARD;  			break;  		} @@ -2320,25 +2163,14 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)  			dev_close(card->dev);  			rtnl_unlock();  		} -		if (!card->use_hard_stop) { -			rc = qeth_send_stoplan(card); -			if (rc) -				QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); -		}  		card->state = CARD_STATE_SOFTSETUP;  	}  	if (card->state == CARD_STATE_SOFTSETUP) { -		qeth_l3_clear_ip_list(card, !card->use_hard_stop, 1); +		qeth_l3_clear_ip_list(card, 1);  		qeth_clear_ipacmd_list(card);  		card->state = CARD_STATE_HARDSETUP;  	}  	if (card->state == CARD_STATE_HARDSETUP) { -		if (!card->use_hard_stop && -		    (card->info.type != QETH_CARD_TYPE_IQD)) { -			rc = qeth_l3_put_unique_id(card); -			if (rc) -				QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); -		}  		qeth_qdio_clear_card(card, 0);  		qeth_clear_qdio_buffers(card);  		qeth_clear_working_pool_list(card); @@ -2348,7 +2180,6 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)  		qeth_clear_cmd_buffers(&card->read);  		qeth_clear_cmd_buffers(&card->write);  	} -	card->use_hard_stop = 0;  	return rc;  } @@ -2455,22 +2286,46 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)  	return rc;  } -static void qeth_l3_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo, -		struct qeth_arp_query_data *qdata, int entry_size, -		int uentry_size) +static __u32 get_arp_entry_size(struct qeth_card *card, +			struct qeth_arp_query_data *qdata, +			struct qeth_arp_entrytype *type, __u8 strip_entries)  { -	char *entry_ptr; -	char *uentry_ptr; -	int i; +	__u32 rc; +	__u8 is_hsi; -	entry_ptr = (char *)&qdata->data; -	uentry_ptr = (char *)(qinfo->udata + qinfo->udata_offset); -	for (i = 0; i < qdata->no_entries; ++i) { -		/* strip off 32 bytes "media specific information" */ -		memcpy(uentry_ptr, (entry_ptr + 32), entry_size - 32); -		entry_ptr += entry_size; -		uentry_ptr += uentry_size; +	is_hsi = qdata->reply_bits == 5; +	if (type->ip == QETHARP_IP_ADDR_V4) { +		QETH_CARD_TEXT(card, 4, "arpev4"); +		if (strip_entries) { +			rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5_short) : +				sizeof(struct qeth_arp_qi_entry7_short); +		} else { +			rc = is_hsi ? sizeof(struct qeth_arp_qi_entry5) : +				sizeof(struct qeth_arp_qi_entry7); +		} +	} else if (type->ip == QETHARP_IP_ADDR_V6) { +		QETH_CARD_TEXT(card, 4, "arpev6"); +		if (strip_entries) { +			rc = is_hsi ? +				sizeof(struct qeth_arp_qi_entry5_short_ipv6) : +				sizeof(struct qeth_arp_qi_entry7_short_ipv6); +		} else { +			rc = is_hsi ? +				sizeof(struct qeth_arp_qi_entry5_ipv6) : +				sizeof(struct qeth_arp_qi_entry7_ipv6); +		} +	} else { +		QETH_CARD_TEXT(card, 4, "arpinv"); +		rc = 0;  	} + +	return rc; +} + +static int arpentry_matches_prot(struct qeth_arp_entrytype *type, __u16 prot) +{ +	return (type->ip == QETHARP_IP_ADDR_V4 && prot == QETH_PROT_IPV4) || +		(type->ip == QETHARP_IP_ADDR_V6 && prot == QETH_PROT_IPV6);  }  static int qeth_l3_arp_query_cb(struct qeth_card *card, @@ -2479,72 +2334,77 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,  	struct qeth_ipa_cmd *cmd;  	struct qeth_arp_query_data *qdata;  	struct qeth_arp_query_info *qinfo; -	int entry_size; -	int uentry_size;  	int i; +	int e; +	int entrybytes_done; +	int stripped_bytes; +	__u8 do_strip_entries; -	QETH_CARD_TEXT(card, 4, "arpquecb"); +	QETH_CARD_TEXT(card, 3, "arpquecb");  	qinfo = (struct qeth_arp_query_info *) reply->param;  	cmd = (struct qeth_ipa_cmd *) data; +	QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.prot_version);  	if (cmd->hdr.return_code) { -		QETH_CARD_TEXT_(card, 4, "qaer1%i", cmd->hdr.return_code); +		QETH_CARD_TEXT(card, 4, "arpcberr"); +		QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);  		return 0;  	}  	if (cmd->data.setassparms.hdr.return_code) {  		cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code; -		QETH_CARD_TEXT_(card, 4, "qaer2%i", cmd->hdr.return_code); +		QETH_CARD_TEXT(card, 4, "setaperr"); +		QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);  		return 0;  	}  	qdata = &cmd->data.setassparms.data.query_arp; -	switch (qdata->reply_bits) { -	case 5: -		uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry5); -		if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) -			uentry_size = sizeof(struct qeth_arp_qi_entry5_short); -		break; -	case 7: -		/* fall through to default */ -	default: -		/* tr is the same as eth -> entry7 */ -		uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry7); -		if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) -			uentry_size = sizeof(struct qeth_arp_qi_entry7_short); -		break; -	} -	/* check if there is enough room in userspace */ -	if ((qinfo->udata_len - qinfo->udata_offset) < -			qdata->no_entries * uentry_size){ -		QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM); -		cmd->hdr.return_code = -ENOMEM; -		goto out_error; -	} -	QETH_CARD_TEXT_(card, 4, "anore%i", -		       cmd->data.setassparms.hdr.number_of_replies); -	QETH_CARD_TEXT_(card, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);  	QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries); -	if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) { -		/* strip off "media specific information" */ -		qeth_l3_copy_arp_entries_stripped(qinfo, qdata, entry_size, -					       uentry_size); -	} else -		/*copy entries to user buffer*/ -		memcpy(qinfo->udata + qinfo->udata_offset, -		       (char *)&qdata->data, qdata->no_entries*uentry_size); +	do_strip_entries = (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) > 0; +	stripped_bytes = do_strip_entries ? QETH_QARP_MEDIASPECIFIC_BYTES : 0; +	entrybytes_done = 0; +	for (e = 0; e < qdata->no_entries; ++e) { +		char *cur_entry; +		__u32 esize; +		struct qeth_arp_entrytype *etype; + +		cur_entry = &qdata->data + entrybytes_done; +		etype = &((struct qeth_arp_qi_entry5 *) cur_entry)->type; +		if (!arpentry_matches_prot(etype, cmd->hdr.prot_version)) { +			QETH_CARD_TEXT(card, 4, "pmis"); +			QETH_CARD_TEXT_(card, 4, "%i", etype->ip); +			break; +		} +		esize = get_arp_entry_size(card, qdata, etype, +			do_strip_entries); +		QETH_CARD_TEXT_(card, 5, "esz%i", esize); +		if (!esize) +			break; -	qinfo->no_entries += qdata->no_entries; -	qinfo->udata_offset += (qdata->no_entries*uentry_size); +		if ((qinfo->udata_len - qinfo->udata_offset) < esize) { +			QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM); +			cmd->hdr.return_code = IPA_RC_ENOMEM; +			goto out_error; +		} + +		memcpy(qinfo->udata + qinfo->udata_offset, +			&qdata->data + entrybytes_done + stripped_bytes, +			esize); +		entrybytes_done += esize + stripped_bytes; +		qinfo->udata_offset += esize; +		++qinfo->no_entries; +	}  	/* check if all replies received ... */  	if (cmd->data.setassparms.hdr.seq_no <  	    cmd->data.setassparms.hdr.number_of_replies)  		return 1; +	QETH_CARD_TEXT_(card, 4, "nove%i", qinfo->no_entries);  	memcpy(qinfo->udata, &qinfo->no_entries, 4);  	/* keep STRIP_ENTRIES flag so the user program can distinguish  	 * stripped entries from normal ones */  	if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)  		qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES;  	memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2); +	QETH_CARD_TEXT_(card, 4, "rc%i", 0);  	return 0;  out_error:  	i = 0; @@ -2567,45 +2427,86 @@ static int qeth_l3_send_ipa_arp_cmd(struct qeth_card *card,  				      reply_cb, reply_param);  } -static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) +static int qeth_l3_query_arp_cache_info(struct qeth_card *card, +	enum qeth_prot_versions prot, +	struct qeth_arp_query_info *qinfo)  {  	struct qeth_cmd_buffer *iob; -	struct qeth_arp_query_info qinfo = {0, }; +	struct qeth_ipa_cmd *cmd;  	int tmp;  	int rc; +	QETH_CARD_TEXT_(card, 3, "qarpipv%i", prot); + +	iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING, +			IPA_CMD_ASS_ARP_QUERY_INFO, +			sizeof(struct qeth_arp_query_data) - sizeof(char), +			prot); +	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); +	cmd->data.setassparms.data.query_arp.request_bits = 0x000F; +	cmd->data.setassparms.data.query_arp.reply_bits = 0; +	cmd->data.setassparms.data.query_arp.no_entries = 0; +	rc = qeth_l3_send_ipa_arp_cmd(card, iob, +			   QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN, +			   qeth_l3_arp_query_cb, (void *)qinfo); +	if (rc) { +		tmp = rc; +		QETH_DBF_MESSAGE(2, +			"Error while querying ARP cache on %s: %s " +			"(0x%x/%d)\n", QETH_CARD_IFNAME(card), +			qeth_l3_arp_get_error_cause(&rc), tmp, tmp); +	} + +	return rc; +} + +static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) +{ +	struct qeth_arp_query_info qinfo = {0, }; +	int rc; +  	QETH_CARD_TEXT(card, 3, "arpquery");  	if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/  			       IPA_ARP_PROCESSING)) { -		return -EOPNOTSUPP; +		QETH_CARD_TEXT(card, 3, "arpqnsup"); +		rc = -EOPNOTSUPP; +		goto out;  	}  	/* get size of userspace buffer and mask_bits -> 6 bytes */ -	if (copy_from_user(&qinfo, udata, 6)) -		return -EFAULT; +	if (copy_from_user(&qinfo, udata, 6)) { +		rc = -EFAULT; +		goto out; +	}  	qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL); -	if (!qinfo.udata) -		return -ENOMEM; +	if (!qinfo.udata) { +		rc = -ENOMEM; +		goto out; +	}  	qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET; -	iob = qeth_l3_get_setassparms_cmd(card, IPA_ARP_PROCESSING, -				       IPA_CMD_ASS_ARP_QUERY_INFO, -				       sizeof(int), QETH_PROT_IPV4); - -	rc = qeth_l3_send_ipa_arp_cmd(card, iob, -				   QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN, -				   qeth_l3_arp_query_cb, (void *)&qinfo); +	rc = qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV4, &qinfo);  	if (rc) { -		tmp = rc; -		QETH_DBF_MESSAGE(2, "Error while querying ARP cache on %s: %s " -			"(0x%x/%d)\n", QETH_CARD_IFNAME(card), -			qeth_l3_arp_get_error_cause(&rc), tmp, tmp);  		if (copy_to_user(udata, qinfo.udata, 4))  			rc = -EFAULT; +			goto free_and_out;  	} else { -		if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) +#ifdef CONFIG_QETH_IPV6 +		if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) { +			/* fails in case of GuestLAN QDIO mode */ +			qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, +				&qinfo); +		} +#endif +		if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) { +			QETH_CARD_TEXT(card, 4, "qactf");  			rc = -EFAULT; +			goto free_and_out; +		} +		QETH_CARD_TEXT_(card, 4, "qacts");  	} +free_and_out:  	kfree(qinfo.udata); +out:  	return rc;  } @@ -2796,6 +2697,9 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)  							mii_data->phy_id,  							mii_data->reg_num);  		break; +	case SIOC_QETH_QUERY_OAT: +		rc = qeth_query_oat_command(card, rq->ifr_ifru.ifru_data); +		break;  	default:  		rc = -EOPNOTSUPP;  	} @@ -2807,9 +2711,17 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)  int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)  {  	int cast_type = RTN_UNSPEC; +	struct neighbour *n = NULL; +	struct dst_entry *dst; -	if (skb_dst(skb) && skb_dst(skb)->neighbour) { -		cast_type = skb_dst(skb)->neighbour->type; +	rcu_read_lock(); +	dst = skb_dst(skb); +	if (dst) +		n = dst_neigh_lookup_skb(dst, skb); +	if (n) { +		cast_type = n->type; +		rcu_read_unlock(); +		neigh_release(n);  		if ((cast_type == RTN_BROADCAST) ||  		    (cast_type == RTN_MULTICAST) ||  		    (cast_type == RTN_ANYCAST)) @@ -2817,6 +2729,8 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)  		else  			return RTN_UNSPEC;  	} +	rcu_read_unlock(); +  	/* try something else */  	if (skb->protocol == ETH_P_IPV6)  		return (skb_network_header(skb)[24] == 0xff) ? @@ -2849,9 +2763,35 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)  	return cast_type;  } +static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, +		struct qeth_hdr *hdr, struct sk_buff *skb) +{ +	char daddr[16]; +	struct af_iucv_trans_hdr *iucv_hdr; + +	skb_pull(skb, 14); +	card->dev->header_ops->create(skb, card->dev, 0, +				      card->dev->dev_addr, card->dev->dev_addr, +				      card->dev->addr_len); +	skb_pull(skb, 14); +	iucv_hdr = (struct af_iucv_trans_hdr *)skb->data; +	memset(hdr, 0, sizeof(struct qeth_hdr)); +	hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; +	hdr->hdr.l3.ext_flags = 0; +	hdr->hdr.l3.length = skb->len; +	hdr->hdr.l3.flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; +	memset(daddr, 0, sizeof(daddr)); +	daddr[0] = 0xfe; +	daddr[1] = 0x80; +	memcpy(&daddr[8], iucv_hdr->destUserID, 8); +	memcpy(hdr->hdr.l3.dest_addr, daddr, 16); +} +  static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,  		struct sk_buff *skb, int ipv, int cast_type)  { +	struct dst_entry *dst; +  	memset(hdr, 0, sizeof(struct qeth_hdr));  	hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;  	hdr->hdr.l3.ext_flags = 0; @@ -2860,7 +2800,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,  	 * before we're going to overwrite this location with next hop ip.  	 * v6 uses passthrough, v4 sets the tag in the QDIO header.  	 */ -	if (card->vlangrp && vlan_tx_tag_present(skb)) { +	if (vlan_tx_tag_present(skb)) {  		if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD))  			hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME;  		else @@ -2869,39 +2809,34 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,  	}  	hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr); + +	rcu_read_lock(); +	dst = skb_dst(skb);  	if (ipv == 4) { +		struct rtable *rt = (struct rtable *) dst; +		__be32 *pkey = &ip_hdr(skb)->daddr; + +		if (rt->rt_gateway) +			pkey = &rt->rt_gateway; +  		/* IPv4 */  		hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type);  		memset(hdr->hdr.l3.dest_addr, 0, 12); -		if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { -			*((u32 *) (&hdr->hdr.l3.dest_addr[12])) = -			    *((u32 *) skb_dst(skb)->neighbour->primary_key); -		} else { -			/* fill in destination address used in ip header */ -			*((u32 *) (&hdr->hdr.l3.dest_addr[12])) = -							ip_hdr(skb)->daddr; -		} +		*((__be32 *) (&hdr->hdr.l3.dest_addr[12])) = *pkey;  	} else if (ipv == 6) { +		struct rt6_info *rt = (struct rt6_info *) dst; +		struct in6_addr *pkey = &ipv6_hdr(skb)->daddr; + +		if (!ipv6_addr_any(&rt->rt6i_gateway)) +			pkey = &rt->rt6i_gateway; +  		/* IPv6 */  		hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type);  		if (card->info.type == QETH_CARD_TYPE_IQD)  			hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; -		if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { -			memcpy(hdr->hdr.l3.dest_addr, -			       skb_dst(skb)->neighbour->primary_key, 16); -		} else { -			/* fill in destination address used in ip header */ -			memcpy(hdr->hdr.l3.dest_addr, -			       &ipv6_hdr(skb)->daddr, 16); -		} +		memcpy(hdr->hdr.l3.dest_addr, pkey, 16);  	} else { -		/* passthrough */ -		if ((skb->dev->type == ARPHRD_IEEE802_TR) && -			!memcmp(skb->data + sizeof(struct qeth_hdr) + -			sizeof(__u16), skb->dev->broadcast, 6)) { -			hdr->hdr.l3.flags = QETH_CAST_BROADCAST | -						QETH_HDR_PASSTHRU; -		} else if (!memcmp(skb->data + sizeof(struct qeth_hdr), +		if (!memcmp(skb->data + sizeof(struct qeth_hdr),  			    skb->dev->broadcast, 6)) {  			/* broadcast? */  			hdr->hdr.l3.flags = QETH_CAST_BROADCAST | @@ -2912,6 +2847,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,  				QETH_CAST_UNICAST | QETH_HDR_PASSTHRU;  		}  	} +	rcu_read_unlock();  }  static inline void qeth_l3_hdr_csum(struct qeth_card *card, @@ -2924,7 +2860,9 @@ static inline void qeth_l3_hdr_csum(struct qeth_card *card,  	 */  	if (iph->protocol == IPPROTO_UDP)  		hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_UDP; -	hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ; +	hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ | +		QETH_HDR_EXT_CSUM_HDR_REQ; +	iph->check = 0;  	if (card->options.performance_stats)  		card->perf_stats.tx_csum++;  } @@ -2971,7 +2909,9 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb)  		tcp_hdr(skb)->doff * 4;  	int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data);  	int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd); -	elements += skb_shinfo(skb)->nr_frags; + +	elements += qeth_get_elements_for_frags(skb); +  	return elements;  } @@ -2986,15 +2926,21 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  	struct sk_buff *new_skb = NULL;  	int ipv = qeth_get_ip_version(skb);  	int cast_type = qeth_l3_get_cast_type(card, skb); -	struct qeth_qdio_out_q *queue = card->qdio.out_qs -		[qeth_get_priority_queue(card, skb, ipv, cast_type)]; +	struct qeth_qdio_out_q *queue = +		card->qdio.out_qs[card->qdio.do_prio_queueing +			|| (cast_type && card->info.is_multicast_different) ? +			qeth_get_priority_queue(card, skb, ipv, cast_type) : +			card->qdio.default_out_queue];  	int tx_bytes = skb->len; -	enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; +	bool large_send;  	int data_offset = -1;  	int nr_frags; -	if (((card->info.type == QETH_CARD_TYPE_IQD) && (!ipv)) || -	     card->options.sniffer) +	if (((card->info.type == QETH_CARD_TYPE_IQD) && +	     (((card->options.cq != QETH_CQ_ENABLED) && !ipv) || +	      ((card->options.cq == QETH_CQ_ENABLED) && +	       (skb->protocol != ETH_P_AF_IUCV)))) || +	    card->options.sniffer)  			goto tx_drop;  	if ((card->state != CARD_STATE_UP) || !card->lan_online) { @@ -3011,13 +2957,15 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  		card->perf_stats.outbound_start_time = qeth_get_micros();  	} -	if (skb_is_gso(skb)) -		large_send = card->options.large_send; +	large_send = skb_is_gso(skb);  	if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&  	    (skb_shinfo(skb)->nr_frags == 0)) {  		new_skb = skb; -		data_offset = ETH_HLEN; +		if (new_skb->protocol == ETH_P_AF_IUCV) +			data_offset = 0; +		else +			data_offset = ETH_HLEN;  		hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);  		if (!hdr)  			goto tx_drop; @@ -3035,14 +2983,10 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  			skb_pull(new_skb, ETH_HLEN);  	} else {  		if (ipv == 4) { -			if (card->dev->type == ARPHRD_IEEE802_TR) -				skb_pull(new_skb, TR_HLEN); -			else -				skb_pull(new_skb, ETH_HLEN); +			skb_pull(new_skb, ETH_HLEN);  		} -		if (ipv == 6 && card->vlangrp && -				vlan_tx_tag_present(new_skb)) { +		if (ipv != 4 && vlan_tx_tag_present(new_skb)) {  			skb_push(new_skb, VLAN_HLEN);  			skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4);  			skb_copy_to_linear_data_offset(new_skb, 4, @@ -3052,7 +2996,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  			tag = (u16 *)(new_skb->data + 12);  			*tag = __constant_htons(ETH_P_8021Q);  			*(tag + 1) = htons(vlan_tx_tag_get(new_skb)); -			new_skb->vlan_tci = 0;  		}  	} @@ -3061,7 +3004,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  	/* fix hardware limitation: as long as we do not have sbal  	 * chaining we can not send long frag lists  	 */ -	if (large_send == QETH_LARGE_SEND_TSO) { +	if (large_send) {  		if (qeth_l3_tso_elements(new_skb) + 1 > 16) {  			if (skb_linearize(new_skb))  				goto tx_drop; @@ -3070,8 +3013,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  		}  	} -	if ((large_send == QETH_LARGE_SEND_TSO) && -	    (cast_type == RTN_UNSPEC)) { +	if (large_send && (cast_type == RTN_UNSPEC)) {  		hdr = (struct qeth_hdr *)skb_push(new_skb,  						sizeof(struct qeth_hdr_tso));  		memset(hdr, 0, sizeof(struct qeth_hdr_tso)); @@ -3085,17 +3027,20 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  			qeth_l3_fill_header(card, hdr, new_skb, ipv,  						cast_type);  		} else { -			qeth_l3_fill_header(card, hdr, new_skb, ipv, -						cast_type); -			hdr->hdr.l3.length = new_skb->len - data_offset; +			if (new_skb->protocol == ETH_P_AF_IUCV) +				qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb); +			else { +				qeth_l3_fill_header(card, hdr, new_skb, ipv, +							cast_type); +				hdr->hdr.l3.length = new_skb->len - data_offset; +			}  		}  		if (skb->ip_summed == CHECKSUM_PARTIAL)  			qeth_l3_hdr_csum(card, hdr, new_skb);  	} -	elems = qeth_get_elements_no(card, (void *)hdr, new_skb, -						 elements_needed); +	elems = qeth_get_elements_no(card, new_skb, elements_needed);  	if (!elems) {  		if (data_offset >= 0)  			kmem_cache_free(qeth_core_header_cache, hdr); @@ -3106,14 +3051,14 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  	if (card->info.type != QETH_CARD_TYPE_IQD) {  		int len; -		if (large_send == QETH_LARGE_SEND_TSO) +		if (large_send)  			len = ((unsigned long)tcp_hdr(new_skb) +  				tcp_hdr(new_skb)->doff * 4) -  				(unsigned long)new_skb->data;  		else  			len = sizeof(struct qeth_hdr_layer3); -		if (qeth_hdr_chk_and_bounce(new_skb, len)) +		if (qeth_hdr_chk_and_bounce(new_skb, &hdr, len))  			goto tx_drop;  		rc = qeth_do_send_packet(card, queue, new_skb, hdr,  					 elements_needed); @@ -3127,7 +3072,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)  		if (new_skb != skb)  			dev_kfree_skb_any(skb);  		if (card->options.performance_stats) { -			if (large_send != QETH_LARGE_SEND_NO) { +			if (large_send) {  				card->perf_stats.large_send_bytes += tx_bytes;  				card->perf_stats.large_send_cnt++;  			} @@ -3166,12 +3111,14 @@ tx_drop:  	return NETDEV_TX_OK;  } -static int qeth_l3_open(struct net_device *dev) +static int __qeth_l3_open(struct net_device *dev)  {  	struct qeth_card *card = dev->ml_priv;  	int rc = 0;  	QETH_CARD_TEXT(card, 4, "qethopen"); +	if (card->state == CARD_STATE_UP) +		return rc;  	if (card->state != CARD_STATE_SOFTSETUP)  		return -ENODEV;  	card->data.state = CH_STATE_UP; @@ -3186,6 +3133,18 @@ static int qeth_l3_open(struct net_device *dev)  	return rc;  } +static int qeth_l3_open(struct net_device *dev) +{ +	struct qeth_card *card = dev->ml_priv; + +	QETH_CARD_TEXT(card, 5, "qethope_"); +	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { +		QETH_CARD_TEXT(card, 3, "openREC"); +		return -ERESTARTSYS; +	} +	return __qeth_l3_open(dev); +} +  static int qeth_l3_stop(struct net_device *dev)  {  	struct qeth_card *card = dev->ml_priv; @@ -3199,65 +3158,44 @@ static int qeth_l3_stop(struct net_device *dev)  	return 0;  } -static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) -{ -	struct qeth_card *card = dev->ml_priv; - -	return (card->options.checksum_type == HW_CHECKSUMMING); -} - -static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) +static netdev_features_t qeth_l3_fix_features(struct net_device *dev, +	netdev_features_t features)  {  	struct qeth_card *card = dev->ml_priv; -	enum qeth_checksum_types csum_type; -	if (data) -		csum_type = HW_CHECKSUMMING; -	else -		csum_type = SW_CHECKSUMMING; +	if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) +		features &= ~NETIF_F_IP_CSUM; +	if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) +		features &= ~NETIF_F_TSO; +	if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) +		features &= ~NETIF_F_RXCSUM; -	return qeth_l3_set_rx_csum(card, csum_type); +	return features;  } -static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) +static int qeth_l3_set_features(struct net_device *dev, +	netdev_features_t features)  {  	struct qeth_card *card = dev->ml_priv; -	int rc = 0; +	u32 changed = dev->features ^ features; +	int err; -	if (data) { -		rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO); -	} else { -		dev->features &= ~NETIF_F_TSO; -		card->options.large_send = QETH_LARGE_SEND_NO; -	} -	return rc; -} +	if (!(changed & NETIF_F_RXCSUM)) +		return 0; -static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data) -{ -	struct qeth_card *card = dev->ml_priv; +	if (card->state == CARD_STATE_DOWN || +	    card->state == CARD_STATE_RECOVER) +		return 0; -	if (data) { -		if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) -			dev->features |= NETIF_F_IP_CSUM; -		else -			return -EPERM; -	} else -		dev->features &= ~NETIF_F_IP_CSUM; +	err = qeth_l3_set_rx_csum(card, features & NETIF_F_RXCSUM); +	if (err) +		dev->features = features ^ NETIF_F_RXCSUM; -	return 0; +	return err;  }  static const struct ethtool_ops qeth_l3_ethtool_ops = {  	.get_link = ethtool_op_get_link, -	.get_tx_csum = ethtool_op_get_tx_csum, -	.set_tx_csum = qeth_l3_ethtool_set_tx_csum, -	.get_rx_csum = qeth_l3_ethtool_get_rx_csum, -	.set_rx_csum = qeth_l3_ethtool_set_rx_csum, -	.get_sg      = ethtool_op_get_sg, -	.set_sg      = ethtool_op_set_sg, -	.get_tso     = ethtool_op_get_tso, -	.set_tso     = qeth_l3_ethtool_set_tso,  	.get_strings = qeth_core_get_strings,  	.get_ethtool_stats = qeth_core_get_ethtool_stats,  	.get_sset_count = qeth_core_get_sset_count, @@ -3295,13 +3233,14 @@ static const struct net_device_ops qeth_l3_netdev_ops = {  	.ndo_get_stats		= qeth_get_stats,  	.ndo_start_xmit		= qeth_l3_hard_start_xmit,  	.ndo_validate_addr	= eth_validate_addr, -	.ndo_set_multicast_list = qeth_l3_set_multicast_list, -	.ndo_do_ioctl	   	= qeth_l3_do_ioctl, -	.ndo_change_mtu	   	= qeth_change_mtu, -	.ndo_vlan_rx_register	= qeth_l3_vlan_rx_register, +	.ndo_set_rx_mode	= qeth_l3_set_multicast_list, +	.ndo_do_ioctl		= qeth_l3_do_ioctl, +	.ndo_change_mtu		= qeth_change_mtu, +	.ndo_fix_features	= qeth_l3_fix_features, +	.ndo_set_features	= qeth_l3_set_features,  	.ndo_vlan_rx_add_vid	= qeth_l3_vlan_rx_add_vid,  	.ndo_vlan_rx_kill_vid   = qeth_l3_vlan_rx_kill_vid, -	.ndo_tx_timeout	   	= qeth_tx_timeout, +	.ndo_tx_timeout		= qeth_tx_timeout,  };  static const struct net_device_ops qeth_l3_osa_netdev_ops = { @@ -3310,13 +3249,14 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {  	.ndo_get_stats		= qeth_get_stats,  	.ndo_start_xmit		= qeth_l3_hard_start_xmit,  	.ndo_validate_addr	= eth_validate_addr, -	.ndo_set_multicast_list = qeth_l3_set_multicast_list, -	.ndo_do_ioctl	   	= qeth_l3_do_ioctl, -	.ndo_change_mtu	   	= qeth_change_mtu, -	.ndo_vlan_rx_register	= qeth_l3_vlan_rx_register, +	.ndo_set_rx_mode	= qeth_l3_set_multicast_list, +	.ndo_do_ioctl		= qeth_l3_do_ioctl, +	.ndo_change_mtu		= qeth_change_mtu, +	.ndo_fix_features	= qeth_l3_fix_features, +	.ndo_set_features	= qeth_l3_set_features,  	.ndo_vlan_rx_add_vid	= qeth_l3_vlan_rx_add_vid,  	.ndo_vlan_rx_kill_vid   = qeth_l3_vlan_rx_kill_vid, -	.ndo_tx_timeout	   	= qeth_tx_timeout, +	.ndo_tx_timeout		= qeth_tx_timeout,  	.ndo_neigh_setup	= qeth_l3_neigh_setup,  }; @@ -3326,12 +3266,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)  	    card->info.type == QETH_CARD_TYPE_OSX) {  		if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||  		    (card->info.link_type == QETH_LINK_TYPE_HSTR)) { -#ifdef CONFIG_TR -			card->dev = alloc_trdev(0); -#endif -			if (!card->dev) -				return -ENODEV; -			card->dev->netdev_ops = &qeth_l3_netdev_ops; +			pr_info("qeth_l3: ignoring TR device\n"); +			return -ENODEV;  		} else {  			card->dev = alloc_etherdev(0);  			if (!card->dev) @@ -3343,6 +3279,12 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)  			if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))  				card->dev->dev_id = card->info.unique_id &  							 0xffff; +			if (!card->info.guestlan) { +				card->dev->hw_features = NETIF_F_SG | +					NETIF_F_RXCSUM | NETIF_F_IP_CSUM | +					NETIF_F_TSO; +				card->dev->features = NETIF_F_RXCSUM; +			}  		}  	} else if (card->info.type == QETH_CARD_TYPE_IQD) {  		card->dev = alloc_netdev(0, "hsi%d", ether_setup); @@ -3351,16 +3293,18 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)  		card->dev->flags |= IFF_NOARP;  		card->dev->netdev_ops = &qeth_l3_netdev_ops;  		qeth_l3_iqd_read_initial_mac(card); +		if (card->options.hsuid[0]) +			memcpy(card->dev->perm_addr, card->options.hsuid, 9);  	} else  		return -ENODEV;  	card->dev->ml_priv = card;  	card->dev->watchdog_timeo = QETH_TX_TIMEOUT;  	card->dev->mtu = card->info.initial_mtu; -	SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops); -	card->dev->features |=	NETIF_F_HW_VLAN_TX | -				NETIF_F_HW_VLAN_RX | -				NETIF_F_HW_VLAN_FILTER; +	card->dev->ethtool_ops = &qeth_l3_ethtool_ops; +	card->dev->features |=	NETIF_F_HW_VLAN_CTAG_TX | +				NETIF_F_HW_VLAN_CTAG_RX | +				NETIF_F_HW_VLAN_CTAG_FILTER;  	card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;  	card->dev->gso_max_size = 15 * PAGE_SIZE; @@ -3375,12 +3319,7 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev)  	qeth_l3_create_device_attributes(&gdev->dev);  	card->options.layer2 = 0; -	card->discipline.start_poll = qeth_qdio_start_poll; -	card->discipline.input_handler = (qdio_handler_t *) -		qeth_qdio_input_handler; -	card->discipline.output_handler = (qdio_handler_t *) -		qeth_qdio_output_handler; -	card->discipline.recover = qeth_l3_recover; +	card->info.hwtrap = 0;  	return 0;  } @@ -3393,17 +3332,15 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)  	qeth_set_allowed_threads(card, 0, 1);  	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); -	if (cgdev->state == CCWGROUP_ONLINE) { -		card->use_hard_stop = 1; +	if (cgdev->state == CCWGROUP_ONLINE)  		qeth_l3_set_offline(cgdev); -	}  	if (card->dev) {  		unregister_netdev(card->dev);  		card->dev = NULL;  	} -	qeth_l3_clear_ip_list(card, 0, 0); +	qeth_l3_clear_ip_list(card, 0);  	qeth_l3_clear_ipato_list(card);  	return;  } @@ -3414,7 +3351,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)  	int rc = 0;  	enum qeth_card_states recover_flag; -	BUG_ON(!card);  	mutex_lock(&card->discipline_mutex);  	mutex_lock(&card->conf_mutex);  	QETH_DBF_TEXT(SETUP, 2, "setonlin"); @@ -3428,13 +3364,18 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)  		goto out_remove;  	} -	qeth_l3_query_ipassists(card, QETH_PROT_IPV4); -  	if (!card->dev && qeth_l3_setup_netdev(card)) {  		rc = -ENODEV;  		goto out_remove;  	} +	if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { +		if (card->info.hwtrap && +		    qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)) +			card->info.hwtrap = 0; +	} else +		card->info.hwtrap = 0; +  	card->state = CARD_STATE_HARDSETUP;  	memset(&card->rx, 0, sizeof(struct qeth_rx));  	qeth_print_status_message(card); @@ -3462,9 +3403,10 @@ contin:  		QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);  	if (!card->options.sniffer) {  		rc = qeth_l3_start_ipassists(card); -		if (rc) +		if (rc) {  			QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); -		qeth_l3_set_large_send(card, card->options.large_send); +			goto out_remove; +		}  		rc = qeth_l3_setrouting_v4(card);  		if (rc)  			QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); @@ -3489,26 +3431,26 @@ contin:  	else  		netif_carrier_off(card->dev);  	if (recover_flag == CARD_STATE_RECOVER) { +		rtnl_lock();  		if (recovery_mode) -			qeth_l3_open(card->dev); -		else { -			rtnl_lock(); +			__qeth_l3_open(card->dev); +		else  			dev_open(card->dev); -			rtnl_unlock(); -		}  		qeth_l3_set_multicast_list(card->dev); +		rtnl_unlock();  	} +	qeth_trace_features(card);  	/* let user_space know that device is online */  	kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);  	mutex_unlock(&card->conf_mutex);  	mutex_unlock(&card->discipline_mutex);  	return 0;  out_remove: -	card->use_hard_stop = 1;  	qeth_l3_stop_card(card, 0);  	ccw_device_set_offline(CARD_DDEV(card));  	ccw_device_set_offline(CARD_WDEV(card));  	ccw_device_set_offline(CARD_RDEV(card)); +	qdio_free(CARD_DDEV(card));  	if (recover_flag == CARD_STATE_RECOVER)  		card->state = CARD_STATE_RECOVER;  	else @@ -3538,7 +3480,16 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,  	if (card->dev && netif_carrier_ok(card->dev))  		netif_carrier_off(card->dev);  	recover_flag = card->state; +	if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) { +		qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); +		card->info.hwtrap = 1; +	}  	qeth_l3_stop_card(card, recovery_mode); +	if ((card->options.cq == QETH_CQ_ENABLED) && card->dev) { +		rtnl_lock(); +		call_netdevice_notifiers(NETDEV_REBOOT, card->dev); +		rtnl_unlock(); +	}  	rc  = ccw_device_set_offline(CARD_DDEV(card));  	rc2 = ccw_device_set_offline(CARD_WDEV(card));  	rc3 = ccw_device_set_offline(CARD_RDEV(card)); @@ -3546,6 +3497,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,  		rc = (rc2) ? rc2 : rc3;  	if (rc)  		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); +	qdio_free(CARD_DDEV(card));  	if (recover_flag == CARD_STATE_UP)  		card->state = CARD_STATE_RECOVER;  	/* let user_space know that device is offline */ @@ -3573,19 +3525,18 @@ static int qeth_l3_recover(void *ptr)  	QETH_CARD_TEXT(card, 2, "recover2");  	dev_warn(&card->gdev->dev,  		"A recovery process has been started for the device\n"); -	card->use_hard_stop = 1; +	qeth_set_recovery_task(card);  	__qeth_l3_set_offline(card->gdev, 1);  	rc = __qeth_l3_set_online(card->gdev, 1);  	if (!rc)  		dev_info(&card->gdev->dev,  			"Device successfully recovered!\n");  	else { -		rtnl_lock(); -		dev_close(card->dev); -		rtnl_unlock(); +		qeth_close_dev(card);  		dev_warn(&card->gdev->dev, "The qeth device driver " -			"failed to recover an error on the device\n"); +				"failed to recover an error on the device\n");  	} +	qeth_clear_recovery_task(card);  	qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);  	qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);  	return 0; @@ -3594,9 +3545,12 @@ static int qeth_l3_recover(void *ptr)  static void qeth_l3_shutdown(struct ccwgroup_device *gdev)  {  	struct qeth_card *card = dev_get_drvdata(&gdev->dev); -	qeth_l3_clear_ip_list(card, 0, 0); +	qeth_set_allowed_threads(card, 0, 1); +	if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap) +		qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);  	qeth_qdio_clear_card(card, 0);  	qeth_clear_qdio_buffers(card); +	qdio_free(CARD_DDEV(card));  }  static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) @@ -3610,7 +3564,8 @@ static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)  	if (gdev->state == CCWGROUP_OFFLINE)  		return 0;  	if (card->state == CARD_STATE_UP) { -		card->use_hard_stop = 1; +		if (card->info.hwtrap) +			qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);  		__qeth_l3_set_offline(card->gdev, 1);  	} else  		__qeth_l3_set_offline(card->gdev, 0); @@ -3644,8 +3599,19 @@ out:  	return rc;  } -struct ccwgroup_driver qeth_l3_ccwgroup_driver = { -	.probe = qeth_l3_probe_device, +/* Returns zero if the command is successfully "consumed" */ +static int qeth_l3_control_event(struct qeth_card *card, +					struct qeth_ipa_cmd *cmd) +{ +	return 1; +} + +struct qeth_discipline qeth_l3_discipline = { +	.start_poll = qeth_qdio_start_poll, +	.input_handler = (qdio_handler_t *) qeth_qdio_input_handler, +	.output_handler = (qdio_handler_t *) qeth_qdio_output_handler, +	.recover = qeth_l3_recover, +	.setup = qeth_l3_probe_device,  	.remove = qeth_l3_remove_device,  	.set_online = qeth_l3_set_online,  	.set_offline = qeth_l3_set_offline, @@ -3653,8 +3619,9 @@ struct ccwgroup_driver qeth_l3_ccwgroup_driver = {  	.freeze = qeth_l3_pm_suspend,  	.thaw = qeth_l3_pm_resume,  	.restore = qeth_l3_pm_resume, +	.control_event_handler = qeth_l3_control_event,  }; -EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); +EXPORT_SYMBOL_GPL(qeth_l3_discipline);  static int qeth_l3_ip_event(struct notifier_block *this,  			    unsigned long event, void *ptr) @@ -3668,9 +3635,9 @@ static int qeth_l3_ip_event(struct notifier_block *this,  		return NOTIFY_DONE;  	card = qeth_l3_get_card_from_dev(dev); -	QETH_CARD_TEXT(card, 3, "ipevent");  	if (!card)  		return NOTIFY_DONE; +	QETH_CARD_TEXT(card, 3, "ipevent");  	addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);  	if (addr != NULL) { @@ -3714,7 +3681,6 @@ static int qeth_l3_ip6_event(struct notifier_block *this,  	struct qeth_ipaddr *addr;  	struct qeth_card *card; -  	card = qeth_l3_get_card_from_dev(dev);  	if (!card)  		return NOTIFY_DONE; @@ -3777,9 +3743,9 @@ static void qeth_l3_unregister_notifiers(void)  {  	QETH_DBF_TEXT(SETUP, 5, "unregnot"); -	BUG_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier)); +	WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));  #ifdef CONFIG_QETH_IPV6 -	BUG_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier)); +	WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));  #endif /* QETH_IPV6 */  }  | 
