14a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka/*
24a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka *  drivers/s390/net/qeth_l2_main.c
34a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka *
4bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka *    Copyright IBM Corp. 2007, 2009
54a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
64a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka *		 Frank Pavlic <fpavlic@de.ibm.com>,
74a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka *		 Thomas Spatzier <tspat@de.ibm.com>,
84a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka *		 Frank Blaschka <frank.blaschka@de.ibm.com>
94a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka */
104a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1174eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka#define KMSG_COMPONENT "qeth"
1274eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1374eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka
144a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/module.h>
154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/moduleparam.h>
164a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/string.h>
174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/errno.h>
184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/kernel.h>
195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/etherdevice.h>
214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/mii.h>
224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include <linux/ip.h>
23ccffad25b5136958d4769ed6de5e87992dd9c65cJiri Pirko#include <linux/list.h>
244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka#include "qeth_core.h"
264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
274a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_set_offline(struct ccwgroup_device *);
284a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_stop(struct net_device *);
294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_delmac(struct qeth_card *, __u8 *);
304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setdelmac(struct qeth_card *, __u8 *,
314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   enum qeth_ipa_cmds,
324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   int (*reply_cb) (struct qeth_card *,
334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					    struct qeth_reply*,
344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					    unsigned long));
354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic void qeth_l2_set_multicast_list(struct net_device *);
364a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_recover(void *);
374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
394a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
40509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct mii_ioctl_data *mii_data;
424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!card)
454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if ((card->state != CARD_STATE_UP) &&
484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		(card->state != CARD_STATE_SOFTSETUP))
494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
504a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->info.type == QETH_CARD_TYPE_OSN)
524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -EPERM;
534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	switch (cmd) {
554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	case SIOC_QETH_ADP_SET_SNMP_CONTROL:
564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data);
574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		break;
584a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	case SIOC_QETH_GET_CARD_TYPE:
595113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun		if ((card->info.type == QETH_CARD_TYPE_OSD ||
605113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun		     card->info.type == QETH_CARD_TYPE_OSM ||
615113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun		     card->info.type == QETH_CARD_TYPE_OSX) &&
624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		    !card->info.guestlan)
634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			return 1;
644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return 0;
654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		break;
664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	case SIOCGMIIPHY:
674a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		mii_data = if_mii(rq);
684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		mii_data->phy_id = 0;
694a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		break;
704a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	case SIOCGMIIREG:
714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		mii_data = if_mii(rq);
724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (mii_data->phy_id != 0)
734a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			rc = -EINVAL;
744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		else
754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			mii_data->val_out = qeth_mdio_read(dev,
764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				mii_data->phy_id, mii_data->reg_num);
774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		break;
784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	default:
794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		rc = -EOPNOTSUPP;
804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (rc)
82847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT_(card, 2, "ioce%d", rc);
834a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return rc;
844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_verify_dev(struct net_device *dev)
874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card;
894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	unsigned long flags;
904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	read_lock_irqsave(&qeth_core_card_list.rwlock, flags);
934a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	list_for_each_entry(card, &qeth_core_card_list.list, list) {
944a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (card->dev == dev) {
954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			rc = QETH_REAL_CARD;
964a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			break;
974a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
994a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	read_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
1004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return rc;
1024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
1034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1044a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic struct net_device *qeth_l2_netdev_by_devno(unsigned char *read_dev_no)
1054a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
1064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card;
1074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct net_device *ndev;
108f06f6f3224afdd7e58207d1f5950f4666c5f095fCornelia Huck	__u16 temp_dev_no;
1094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	unsigned long flags;
110f06f6f3224afdd7e58207d1f5950f4666c5f095fCornelia Huck	struct ccw_dev_id read_devid;
1114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	ndev = NULL;
1134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(&temp_dev_no, read_dev_no, 2);
1144a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	read_lock_irqsave(&qeth_core_card_list.rwlock, flags);
1154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	list_for_each_entry(card, &qeth_core_card_list.list, list) {
116f06f6f3224afdd7e58207d1f5950f4666c5f095fCornelia Huck		ccw_device_get_id(CARD_RDEV(card), &read_devid);
117f06f6f3224afdd7e58207d1f5950f4666c5f095fCornelia Huck		if (read_devid.devno == temp_dev_no) {
1184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			ndev = card->dev;
1194a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			break;
1204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
1214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
1224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	read_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
1234a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return ndev;
1244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
1254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setgroupmac_cb(struct qeth_card *card,
1274a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				struct qeth_reply *reply,
1284a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				unsigned long data)
1294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
1304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_ipa_cmd *cmd;
1314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	__u8 *mac;
1324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
133847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Sgmacb");
1344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd = (struct qeth_ipa_cmd *) data;
1354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	mac = &cmd->data.setdelmac.mac[0];
1364a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	/* MAC already registered, needed in couple/uncouple case */
1370666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun	if (cmd->hdr.return_code ==  IPA_RC_L2_DUP_MAC) {
1387c510e4b730a92cecf94ada45c989d8be0200d47Johannes Berg		QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n",
1397c510e4b730a92cecf94ada45c989d8be0200d47Johannes Berg			  mac, QETH_CARD_IFNAME(card));
1404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		cmd->hdr.return_code = 0;
1414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
1424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (cmd->hdr.return_code)
1437c510e4b730a92cecf94ada45c989d8be0200d47Johannes Berg		QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %x\n",
1447c510e4b730a92cecf94ada45c989d8be0200d47Johannes Berg			  mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code);
1454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
1464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
1474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac)
1494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
150847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Sgmac");
1514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC,
1524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					  qeth_l2_send_setgroupmac_cb);
1534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
1544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_delgroupmac_cb(struct qeth_card *card,
1564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				struct qeth_reply *reply,
1574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				unsigned long data)
1584a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
1594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_ipa_cmd *cmd;
1604a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	__u8 *mac;
1614a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
162847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Dgmacb");
1634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd = (struct qeth_ipa_cmd *) data;
1644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	mac = &cmd->data.setdelmac.mac[0];
1654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (cmd->hdr.return_code)
1667c510e4b730a92cecf94ada45c989d8be0200d47Johannes Berg		QETH_DBF_MESSAGE(2, "Could not delete group MAC %pM on %s: %x\n",
1677c510e4b730a92cecf94ada45c989d8be0200d47Johannes Berg			  mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code);
1684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
1694a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
1704a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac)
1724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
173847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Dgmac");
1744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC,
1754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					  qeth_l2_send_delgroupmac_cb);
1764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
1774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1787db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschkastatic void qeth_l2_add_mc(struct qeth_card *card, __u8 *mac, int vmac)
1794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
1804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_mc_mac *mc;
1817db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka	int rc;
1824a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1834a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	mc = kmalloc(sizeof(struct qeth_mc_mac), GFP_ATOMIC);
1844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
18514cc21b6770972e5d1487dbf3a2caaf63cae909aFrank Blaschka	if (!mc)
1864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return;
1874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(mc->mc_addr, mac, OSA_ADDR_LEN);
1894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	mc->mc_addrlen = OSA_ADDR_LEN;
1907db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka	mc->is_vmac = vmac;
1917db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka
1927db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka	if (vmac) {
1937db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka		rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC,
1947db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka					NULL);
1957db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka	} else {
1967db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka		rc = qeth_l2_send_setgroupmac(card, mac);
1977db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka	}
1984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1997db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka	if (!rc)
2004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		list_add_tail(&mc->list, &card->mc_list);
2014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	else
2024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		kfree(mc);
2034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
2044a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
20570919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braunstatic void qeth_l2_del_all_mc(struct qeth_card *card, int del)
2064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
2074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_mc_mac *mc, *tmp;
2084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
2094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_lock_bh(&card->mclock);
2104a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	list_for_each_entry_safe(mc, tmp, &card->mc_list, list) {
21170919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun		if (del) {
21270919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun			if (mc->is_vmac)
21370919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun				qeth_l2_send_setdelmac(card, mc->mc_addr,
2147db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka					IPA_CMD_DELVMAC, NULL);
21570919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun			else
21670919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun				qeth_l2_send_delgroupmac(card, mc->mc_addr);
21770919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun		}
2184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		list_del(&mc->list);
2194a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		kfree(mc);
2204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
2214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_unlock_bh(&card->mclock);
2224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
2234a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
224ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wackerstatic inline int qeth_l2_get_cast_type(struct qeth_card *card,
225ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker			struct sk_buff *skb)
2264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
227ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker	if (card->info.type == QETH_CARD_TYPE_OSN)
228ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker		return RTN_UNSPEC;
229ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker	if (is_broadcast_ether_addr(skb->data))
230ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker		return RTN_BROADCAST;
231ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker	if (is_multicast_ether_addr(skb->data))
232ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker		return RTN_MULTICAST;
233ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker	return RTN_UNSPEC;
2344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
2354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
2364a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
2374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			struct sk_buff *skb, int ipv, int cast_type)
2384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
239683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
2404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
2414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memset(hdr, 0, sizeof(struct qeth_hdr));
2424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
2434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
2444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	/* set byte byte 3 to casting flags */
2454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (cast_type == RTN_MULTICAST)
2464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_MULTICAST;
2474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	else if (cast_type == RTN_BROADCAST)
2484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_BROADCAST;
2494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	else
250ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_UNICAST;
2514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
2524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	hdr->hdr.l2.pkt_length = skb->len-QETH_HEADER_SIZE;
2534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	/* VSWITCH relies on the VLAN
2544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	 * information to be present in
2554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	 * the QDIO header */
2564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (veth->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
2574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		hdr->hdr.l2.flags[2] |= QETH_LAYER2_FLAG_VLAN;
2584a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		hdr->hdr.l2.vlan_id = ntohs(veth->h_vlan_TCI);
2594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
2604a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
2614a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
2624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
2634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			struct qeth_reply *reply, unsigned long data)
2644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
2654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_ipa_cmd *cmd;
2664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
267847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2sdvcb");
2684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd = (struct qeth_ipa_cmd *) data;
2694a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (cmd->hdr.return_code) {
27014cc21b6770972e5d1487dbf3a2caaf63cae909aFrank Blaschka		QETH_DBF_MESSAGE(2, "Error in processing VLAN %i on %s: 0x%x. "
2714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			  "Continuing\n", cmd->data.setdelvlan.vlan_id,
2724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			  QETH_CARD_IFNAME(card), cmd->hdr.return_code);
273847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
274847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
2754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
2764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
2774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
2784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
2794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
2804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				enum qeth_ipa_cmds ipacmd)
2814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
2824a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_ipa_cmd *cmd;
2834a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_cmd_buffer *iob;
2844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
285847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd);
2864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
2874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
2884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd->data.setdelvlan.vlan_id = i;
2894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return qeth_send_ipa_cmd(card, iob,
2904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				 qeth_l2_send_setdelvlan_cb, NULL);
2914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
2924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
29370919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braunstatic void qeth_l2_process_vlans(struct qeth_card *card)
2944a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
2954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_vlan_vid *id;
296847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 3, "L2prcvln");
2974a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_lock_bh(&card->vlanlock);
2984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	list_for_each_entry(id, &card->vid_list, list) {
29970919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun		qeth_l2_send_setdelvlan(card, id->vid, IPA_CMD_SETVLAN);
3004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
3014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_unlock_bh(&card->vlanlock);
3024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
3034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
3048e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirkostatic int qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
3054a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
306509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
3074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_vlan_vid *id;
3084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
309847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
31010651db75a94c54a34bbf85fbee334d1114da3fbUrsula Braun	if (!vid)
3118e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko		return 0;
3125113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	if (card->info.type == QETH_CARD_TYPE_OSM) {
313847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 3, "aidOSM");
3148e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko		return 0;
3155113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	}
3168e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
317847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 3, "aidREC");
3188e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko		return 0;
3198e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	}
3204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	id = kmalloc(sizeof(struct qeth_vlan_vid), GFP_ATOMIC);
3214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (id) {
3224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		id->vid = vid;
3234a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN);
3244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		spin_lock_bh(&card->vlanlock);
3254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		list_add_tail(&id->list, &card->vid_list);
3264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		spin_unlock_bh(&card->vlanlock);
3278e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko	} else {
3288e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko		return -ENOMEM;
3294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
3308e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko	return 0;
3314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
3324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
3338e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirkostatic int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
3344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
3354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_vlan_vid *id, *tmpid = NULL;
336509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
3374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
338847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
3395113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	if (card->info.type == QETH_CARD_TYPE_OSM) {
340847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 3, "kidOSM");
3418e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko		return 0;
3425113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	}
3438e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
344847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 3, "kidREC");
3458e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko		return 0;
3468e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	}
3474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_lock_bh(&card->vlanlock);
3484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	list_for_each_entry(id, &card->vid_list, list) {
3494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (id->vid == vid) {
3504a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			list_del(&id->list);
3514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			tmpid = id;
3524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			break;
3534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
3544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
3554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_unlock_bh(&card->vlanlock);
3564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (tmpid) {
3574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
3584a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		kfree(tmpid);
3594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
3604a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_l2_set_multicast_list(card->dev);
3618e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko	return 0;
3624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
3634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
3644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
3654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
3664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
3674a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
368d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_TEXT(SETUP , 2, "stopcard");
369d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
3704a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
3714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_set_allowed_threads(card, 0, 1);
3724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->read.state == CH_STATE_UP &&
3734a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	    card->write.state == CH_STATE_UP &&
3744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	    (card->state == CARD_STATE_UP)) {
3754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (recovery_mode &&
3764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		    card->info.type != QETH_CARD_TYPE_OSN) {
3774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			qeth_l2_stop(card->dev);
3784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		} else {
3794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			rtnl_lock();
3804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			dev_close(card->dev);
3814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			rtnl_unlock();
3824a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
38370919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun		card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
3844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->state = CARD_STATE_SOFTSETUP;
3854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
3864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->state == CARD_STATE_SOFTSETUP) {
38770919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun		qeth_l2_del_all_mc(card, 0);
3884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_clear_ipacmd_list(card);
3894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->state = CARD_STATE_HARDSETUP;
3904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
3914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->state == CARD_STATE_HARDSETUP) {
3924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_qdio_clear_card(card, 0);
3934a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_clear_qdio_buffers(card);
3944a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_clear_working_pool_list(card);
3954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->state = CARD_STATE_DOWN;
3964a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
3974a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->state == CARD_STATE_DOWN) {
3984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_clear_cmd_buffers(&card->read);
3994a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_clear_cmd_buffers(&card->write);
4004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
4014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return rc;
4024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
4034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
404a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschkastatic int qeth_l2_process_inbound_buffer(struct qeth_card *card,
405a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				int budget, int *done)
4064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
407a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	int work_done = 0;
4084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct sk_buff *skb;
4094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_hdr *hdr;
4104a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	unsigned int len;
4114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
412a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	*done = 0;
413a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	BUG_ON(!budget);
414a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	while (budget) {
415a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		skb = qeth_core_get_next_skb(card,
416b333293058aa2d401737c7246bce58f8ba00906dFrank Blaschka			&card->qdio.in_q->bufs[card->rx.b_index],
417a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			&card->rx.b_element, &card->rx.e_offset, &hdr);
418a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		if (!skb) {
419a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			*done = 1;
420a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			break;
4214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
422a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		skb->dev = card->dev;
4234a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		switch (hdr->hdr.l2.id) {
4244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		case QETH_HEADER_TYPE_LAYER2:
4254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			skb->pkt_type = PACKET_HOST;
4264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			skb->protocol = eth_type_trans(skb, skb->dev);
427c5e631a8d4e305a68465b7334efe9875be8b7033Frank Blaschka			skb->ip_summed = CHECKSUM_NONE;
428128837259912087101cd336226abc7ee3e8555b5Ursula Braun			if (skb->protocol == htons(ETH_P_802_2))
429128837259912087101cd336226abc7ee3e8555b5Ursula Braun				*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
4304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			len = skb->len;
431a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			netif_receive_skb(skb);
4324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			break;
4334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		case QETH_HEADER_TYPE_OSN:
4342d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun			if (card->info.type == QETH_CARD_TYPE_OSN) {
4352d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun				skb_push(skb, sizeof(struct qeth_hdr));
4362d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun				skb_copy_to_linear_data(skb, hdr,
4374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka						sizeof(struct qeth_hdr));
4382d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun				len = skb->len;
4392d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun				card->osn_info.data_cb(skb);
4402d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun				break;
4412d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun			}
4422d488c2f514a6c5248a0773c78345626abdc1818Ursula Braun			/* else unknown */
4434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		default:
4444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			dev_kfree_skb_any(skb);
445847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte			QETH_CARD_TEXT(card, 3, "inbunkno");
446d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann			QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN);
4474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			continue;
4484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
449a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		work_done++;
450a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		budget--;
4514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->stats.rx_packets++;
4524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->stats.rx_bytes += len;
4534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
454a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	return work_done;
455a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka}
456a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka
457a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschkastatic int qeth_l2_poll(struct napi_struct *napi, int budget)
458a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka{
459a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	struct qeth_card *card = container_of(napi, struct qeth_card, napi);
460a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	int work_done = 0;
461a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	struct qeth_qdio_buffer *buffer;
462a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	int done;
463a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	int new_budget = budget;
464a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka
465a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	if (card->options.performance_stats) {
466a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		card->perf_stats.inbound_cnt++;
467a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		card->perf_stats.inbound_start_time = qeth_get_micros();
468a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	}
469a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka
470a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	while (1) {
471a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		if (!card->rx.b_count) {
472a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			card->rx.qdio_err = 0;
473a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			card->rx.b_count = qdio_get_next_buffers(
474a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				card->data.ccwdev, 0, &card->rx.b_index,
475a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				&card->rx.qdio_err);
476a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			if (card->rx.b_count <= 0) {
477a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				card->rx.b_count = 0;
478a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				break;
479a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			}
480a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			card->rx.b_element =
481a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				&card->qdio.in_q->bufs[card->rx.b_index]
482a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				.buffer->element[0];
483a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			card->rx.e_offset = 0;
484a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		}
485a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka
486a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		while (card->rx.b_count) {
487a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			buffer = &card->qdio.in_q->bufs[card->rx.b_index];
488a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			if (!(card->rx.qdio_err &&
489a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			    qeth_check_qdio_errors(card, buffer->buffer,
490a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			    card->rx.qdio_err, "qinerr")))
491a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				work_done += qeth_l2_process_inbound_buffer(
492a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka					card, new_budget, &done);
493a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			else
494a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				done = 1;
495a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka
496a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			if (done) {
497a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				if (card->options.performance_stats)
498a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka					card->perf_stats.bufs_rec++;
499a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				qeth_put_buffer_pool_entry(card,
500a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka					buffer->pool_entry);
501a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				qeth_queue_input_buffer(card, card->rx.b_index);
502a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				card->rx.b_count--;
503a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				if (card->rx.b_count) {
504a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka					card->rx.b_index =
505a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka						(card->rx.b_index + 1) %
506a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka						QDIO_MAX_BUFFERS_PER_Q;
507a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka					card->rx.b_element =
508a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka						&card->qdio.in_q
509a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka						->bufs[card->rx.b_index]
510a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka						.buffer->element[0];
511a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka					card->rx.e_offset = 0;
512a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				}
513a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			}
514a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka
515a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			if (work_done >= budget)
516a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				goto out;
517a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			else
518a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka				new_budget = budget - work_done;
519a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		}
520a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	}
521a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka
522a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	napi_complete(napi);
523a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	if (qdio_start_irq(card->data.ccwdev, 0))
524a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		napi_schedule(&card->napi);
525a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschkaout:
526a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	if (card->options.performance_stats)
527a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		card->perf_stats.inbound_time += qeth_get_micros() -
528a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka			card->perf_stats.inbound_start_time;
529a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	return work_done;
5304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
5314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
5324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
5334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   enum qeth_ipa_cmds ipacmd,
5344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   int (*reply_cb) (struct qeth_card *,
5354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					    struct qeth_reply*,
5364a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					    unsigned long))
5374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
5384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_ipa_cmd *cmd;
5394a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_cmd_buffer *iob;
5404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
541847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2sdmac");
5424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
5434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
5444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd->data.setdelmac.mac_length = OSA_ADDR_LEN;
5454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(&cmd->data.setdelmac.mac, mac, OSA_ADDR_LEN);
5464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return qeth_send_ipa_cmd(card, iob, reply_cb, NULL);
5474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
5484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
5494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setmac_cb(struct qeth_card *card,
5504a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   struct qeth_reply *reply,
5514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   unsigned long data)
5524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
5534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_ipa_cmd *cmd;
5544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
555847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Smaccb");
5564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd = (struct qeth_ipa_cmd *) data;
5574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (cmd->hdr.return_code) {
558847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT_(card, 2, "L2er%x", cmd->hdr.return_code);
5594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
5600666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun		switch (cmd->hdr.return_code) {
5610666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun		case IPA_RC_L2_DUP_MAC:
5620666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun		case IPA_RC_L2_DUP_LAYER3_MAC:
5630666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun			dev_warn(&card->gdev->dev,
564d998ab0bd737fad9c8e3c88eb6f52c43e90fda9aH Hartley Sweeten				"MAC address %pM already exists\n",
565221c17fe87033aa154df68679b437c83d835c284Ursula Braun				cmd->data.setdelmac.mac);
5660666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun			break;
5670666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun		case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
5680666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun		case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
5690666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun			dev_warn(&card->gdev->dev,
570d998ab0bd737fad9c8e3c88eb6f52c43e90fda9aH Hartley Sweeten				"MAC address %pM is not authorized\n",
571221c17fe87033aa154df68679b437c83d835c284Ursula Braun				cmd->data.setdelmac.mac);
5720666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun			break;
5730666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun		default:
5740666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun			break;
5750666eb06ab12b1f876719ff5b7d39cf3c609dec3Ursula Braun		}
5764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		cmd->hdr.return_code = -EIO;
5774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	} else {
5784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
5794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac,
5804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		       OSA_ADDR_LEN);
58174eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka		dev_info(&card->gdev->dev,
582d998ab0bd737fad9c8e3c88eb6f52c43e90fda9aH Hartley Sweeten			"MAC address %pM successfully registered on device %s\n",
583d998ab0bd737fad9c8e3c88eb6f52c43e90fda9aH Hartley Sweeten			card->dev->dev_addr, card->dev->name);
5844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
5854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
5864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
5874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
5884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
5894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
590847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Setmac");
5914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC,
5924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					  qeth_l2_send_setmac_cb);
5934a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
5944a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
5954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_delmac_cb(struct qeth_card *card,
5964a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   struct qeth_reply *reply,
5974a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   unsigned long data)
5984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
5994a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_ipa_cmd *cmd;
6004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
601847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Dmaccb");
6024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	cmd = (struct qeth_ipa_cmd *) data;
6034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (cmd->hdr.return_code) {
604847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
6054a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		cmd->hdr.return_code = -EIO;
6064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return 0;
6074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
6084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
6094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6104a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
6114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
6124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
6144a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
615847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "L2Delmac");
6164a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
6174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return 0;
6184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC,
6194a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					  qeth_l2_send_delmac_cb);
6204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
6214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_request_initial_mac(struct qeth_card *card)
6234a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
6244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
6254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	char vendor_pre[] = {0x02, 0x00, 0x00};
6264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
627d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_TEXT(SETUP, 2, "doL2init");
628d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_TEXT_(SETUP, 2, "doL2%s", CARD_BUS_ID(card));
6294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = qeth_query_setadapterparms(card);
6314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (rc) {
63214cc21b6770972e5d1487dbf3a2caaf63cae909aFrank Blaschka		QETH_DBF_MESSAGE(2, "could not query adapter parameters on "
63314cc21b6770972e5d1487dbf3a2caaf63cae909aFrank Blaschka			"device %s: x%x\n", CARD_BUS_ID(card), rc);
6344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
6354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6365113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	if (card->info.type == QETH_CARD_TYPE_IQD ||
6375113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	    card->info.type == QETH_CARD_TYPE_OSM ||
6385113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	    card->info.type == QETH_CARD_TYPE_OSX ||
6395113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	    card->info.guestlan) {
6404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		rc = qeth_setadpparms_change_macaddr(card);
6414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (rc) {
64214cc21b6770972e5d1487dbf3a2caaf63cae909aFrank Blaschka			QETH_DBF_MESSAGE(2, "couldn't get MAC address on "
64314cc21b6770972e5d1487dbf3a2caaf63cae909aFrank Blaschka				"device %s: x%x\n", CARD_BUS_ID(card), rc);
644d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann			QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
6454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			return rc;
6464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
647d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann		QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, OSA_ADDR_LEN);
6484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	} else {
6494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		random_ether_addr(card->dev->dev_addr);
6504a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		memcpy(card->dev->dev_addr, vendor_pre, 3);
6514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
6524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
6534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
6544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_set_mac_address(struct net_device *dev, void *p)
6564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
6574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct sockaddr *addr = p;
658509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
6594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
6604a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
661847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 3, "setmac");
6624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (qeth_l2_verify_dev(dev) != QETH_REAL_CARD) {
664847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 3, "setmcINV");
6654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -EOPNOTSUPP;
6664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
6674a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6685113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	if (card->info.type == QETH_CARD_TYPE_OSN ||
6695113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	    card->info.type == QETH_CARD_TYPE_OSM ||
6705113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	    card->info.type == QETH_CARD_TYPE_OSX) {
671847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 3, "setmcTYP");
6724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -EOPNOTSUPP;
6734a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
674847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_HEX(card, 3, addr->sa_data, OSA_ADDR_LEN);
6758e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
676847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 3, "setmcREC");
6778e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun		return -ERESTARTSYS;
6788e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	}
6794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
6804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!rc)
6814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		rc = qeth_l2_send_setmac(card, addr->sa_data);
6824a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return rc;
6834a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
6844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic void qeth_l2_set_multicast_list(struct net_device *dev)
6864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
687509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
688ccffad25b5136958d4769ed6de5e87992dd9c65cJiri Pirko	struct netdev_hw_addr *ha;
6894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
6904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->info.type == QETH_CARD_TYPE_OSN)
6914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return ;
6924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
693847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 3, "setmulti");
6948e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
6958e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun	    (card->state != CARD_STATE_UP))
6968e98ac48d06068470f1b954e599cf7b706cfcebaUrsula Braun		return;
69770919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun	qeth_l2_del_all_mc(card, 1);
6984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_lock_bh(&card->mclock);
69922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	netdev_for_each_mc_addr(ha, dev)
70022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		qeth_l2_add_mc(card, ha->addr, 0);
7017db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka
70232e7bfc41110bc8f29ec0f293c3bcee6645fef34Jiri Pirko	netdev_for_each_uc_addr(ha, dev)
703ccffad25b5136958d4769ed6de5e87992dd9c65cJiri Pirko		qeth_l2_add_mc(card, ha->addr, 1);
7047db2266a374d66f5ac85334c922cb37d76939cc5Frank Blaschka
7054a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_unlock_bh(&card->mclock);
7064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
7074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return;
7084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_setadp_promisc_mode(card);
7094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
7104a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
7114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
7124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
7134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc;
7144a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_hdr *hdr = NULL;
7154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int elements = 0;
716509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
7174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct sk_buff *new_skb = skb;
7184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int ipv = qeth_get_ip_version(skb);
719ce73e10ee0cb6cde1c5075a2803da0f0eb5b2324Klaus-Dieter Wacker	int cast_type = qeth_l2_get_cast_type(card, skb);
7204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_qdio_out_q *queue = card->qdio.out_qs
7214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
7224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int tx_bytes = skb->len;
723683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka	int data_offset = -1;
724683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka	int elements_needed = 0;
725683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka	int hd_len = 0;
7264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
7274a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if ((card->state != CARD_STATE_UP) || !card->lan_online) {
7284a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->stats.tx_carrier_errors++;
7294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		goto tx_drop;
7304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
7314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
7324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if ((card->info.type == QETH_CARD_TYPE_OSN) &&
7334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	    (skb->protocol == htons(ETH_P_IPV6)))
7344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		goto tx_drop;
7354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
7364a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->options.performance_stats) {
7374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->perf_stats.outbound_cnt++;
7384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->perf_stats.outbound_start_time = qeth_get_micros();
7394a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
7404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	netif_stop_queue(dev);
7414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
7424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->info.type == QETH_CARD_TYPE_OSN)
7434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		hdr = (struct qeth_hdr *)skb->data;
7444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	else {
74564ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka		if (card->info.type == QETH_CARD_TYPE_IQD) {
746683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			new_skb = skb;
747683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			data_offset = ETH_HLEN;
748683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			hd_len = ETH_HLEN;
749683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			hdr = kmem_cache_alloc(qeth_core_header_cache,
750683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka						GFP_ATOMIC);
751683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			if (!hdr)
752683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka				goto tx_drop;
753683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			elements_needed++;
754683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			skb_reset_mac_header(new_skb);
755683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
756683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			hdr->hdr.l2.pkt_length = new_skb->len;
757683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			memcpy(((char *)hdr) + sizeof(struct qeth_hdr),
758683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka				skb_mac_header(new_skb), ETH_HLEN);
759683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka		} else {
760683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			/* create a clone with writeable headroom */
761683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			new_skb = skb_realloc_headroom(skb,
762683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka						sizeof(struct qeth_hdr));
763683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			if (!new_skb)
764683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka				goto tx_drop;
765683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			hdr = (struct qeth_hdr *)skb_push(new_skb,
766f90b744eb8ead0af7a7aa2f78ff861dff4863f2cFrank Blaschka						sizeof(struct qeth_hdr));
767683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			skb_set_mac_header(new_skb, sizeof(struct qeth_hdr));
768683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
769683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka		}
7704a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
7714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
77264ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka	elements = qeth_get_elements_no(card, (void *)hdr, new_skb,
773683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka						elements_needed);
77464ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka	if (!elements) {
77564ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka		if (data_offset >= 0)
77664ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka			kmem_cache_free(qeth_core_header_cache, hdr);
77764ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka		goto tx_drop;
778f61a0d0538ca62547a127fd270d9f3c6e713027fFrank Blaschka	}
7794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
78051aa165c9f27bbfff498e4d56f3eadf17d74c476Frank Blaschka	if (card->info.type != QETH_CARD_TYPE_IQD) {
78151aa165c9f27bbfff498e4d56f3eadf17d74c476Frank Blaschka		if (qeth_hdr_chk_and_bounce(new_skb,
78251aa165c9f27bbfff498e4d56f3eadf17d74c476Frank Blaschka		    sizeof(struct qeth_hdr_layer2)))
78351aa165c9f27bbfff498e4d56f3eadf17d74c476Frank Blaschka			goto tx_drop;
7844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		rc = qeth_do_send_packet(card, queue, new_skb, hdr,
78564ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka					 elements);
78651aa165c9f27bbfff498e4d56f3eadf17d74c476Frank Blaschka	} else
7874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
78864ef8957986f6a04f61e7c95fa6ffeb3a86a6661Frank Blaschka					elements, data_offset, hd_len);
7894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!rc) {
7904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->stats.tx_packets++;
7914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->stats.tx_bytes += tx_bytes;
7924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (new_skb != skb)
7934a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			dev_kfree_skb_any(skb);
794ec634fe328182a1a098585bfc7b69e5042bdb08dPatrick McHardy		rc = NETDEV_TX_OK;
7954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	} else {
796683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka		if (data_offset >= 0)
797683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka			kmem_cache_free(qeth_core_header_cache, hdr);
798683d718a893575a88c551ad71ea2c382eedbf67eFrank Blaschka
7994a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (rc == -EBUSY) {
8004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			if (new_skb != skb)
8014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka				dev_kfree_skb_any(new_skb);
8024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			return NETDEV_TX_BUSY;
8034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		} else
8044a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			goto tx_drop;
8054a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
8064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
8074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	netif_wake_queue(dev);
8084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->options.performance_stats)
8094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->perf_stats.outbound_time += qeth_get_micros() -
8104a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			card->perf_stats.outbound_start_time;
8114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return rc;
8124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
8134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkatx_drop:
8144a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->stats.tx_dropped++;
8154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->stats.tx_errors++;
8164a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if ((new_skb != skb) && new_skb)
8174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		dev_kfree_skb_any(new_skb);
8184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	dev_kfree_skb_any(skb);
819d0ec0f549705b7ecfb787f02512606b08fe5b291Frank Blaschka	netif_wake_queue(dev);
8204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return NETDEV_TX_OK;
8214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
8224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
823394234406c7a8a6b947d230b115c918c0a1def68Ursula Braunstatic int __qeth_l2_open(struct net_device *dev)
8244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
825509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
826a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	int rc = 0;
8274a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
828847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 4, "qethopen");
829394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun	if (card->state == CARD_STATE_UP)
830394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun		return rc;
8314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->state != CARD_STATE_SOFTSETUP)
8324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
8334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
8344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if ((card->info.type != QETH_CARD_TYPE_OSN) &&
8354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	     (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))) {
836847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT(card, 4, "nomacadr");
8374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -EPERM;
8384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
8394a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->data.state = CH_STATE_UP;
8404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->state = CARD_STATE_UP;
8414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	netif_start_queue(dev);
8424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
843a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) {
844a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		napi_enable(&card->napi);
845a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		napi_schedule(&card->napi);
846a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	} else
847a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		rc = -EIO;
848a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	return rc;
8494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
8504a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
851394234406c7a8a6b947d230b115c918c0a1def68Ursula Braunstatic int qeth_l2_open(struct net_device *dev)
852394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun{
853394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun	struct qeth_card *card = dev->ml_priv;
854394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun
855394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun	QETH_CARD_TEXT(card, 5, "qethope_");
856394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun	if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
857394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun		QETH_CARD_TEXT(card, 3, "openREC");
858394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun		return -ERESTARTSYS;
859394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun	}
860394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun	return __qeth_l2_open(dev);
861394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun}
862394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun
8634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_stop(struct net_device *dev)
8644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
865509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	struct qeth_card *card = dev->ml_priv;
8664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
867847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 4, "qethstop");
8684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	netif_tx_disable(dev);
869a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	if (card->state == CARD_STATE_UP) {
8704a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->state = CARD_STATE_SOFTSETUP;
871a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		napi_disable(&card->napi);
872a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	}
8734a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
8744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
8754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
8764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_probe_device(struct ccwgroup_device *gdev)
8774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
8784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
8794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
8804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	INIT_LIST_HEAD(&card->vid_list);
8814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	INIT_LIST_HEAD(&card->mc_list);
8824a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->options.layer2 = 1;
8831da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka	card->info.hwtrap = 0;
884a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	card->discipline.start_poll = qeth_qdio_start_poll;
8854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->discipline.input_handler = (qdio_handler_t *)
886a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka		qeth_qdio_input_handler;
8874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->discipline.output_handler = (qdio_handler_t *)
8884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_qdio_output_handler;
8894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->discipline.recover = qeth_l2_recover;
8904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
8914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
8924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
8934a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
8944a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
8954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
8964a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
897f214856540f6d704e817bf6b26a6bca9e697ee72Ursula Braun	qeth_set_allowed_threads(card, 0, 1);
8984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
8994a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
90070919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun	if (cgdev->state == CCWGROUP_ONLINE)
9014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_l2_set_offline(cgdev);
9024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->dev) {
9044a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		unregister_netdev(card->dev);
9054a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->dev = NULL;
9064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
9074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return;
9084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
9094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9100fc0b732eaa38beb93a6fb62f77c7bd9622c76ecStephen Hemmingerstatic const struct ethtool_ops qeth_l2_ethtool_ops = {
9114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.get_link = ethtool_op_get_link,
9124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.get_strings = qeth_core_get_strings,
9134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.get_ethtool_stats = qeth_core_get_ethtool_stats,
914df8b4ec8b15a5db84706548149add3131c3af8baBen Hutchings	.get_sset_count = qeth_core_get_sset_count,
9154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.get_drvinfo = qeth_core_get_drvinfo,
9163f9975aa4d5b3c614eef8785ec63da13fbd55b51Frank Blaschka	.get_settings = qeth_core_ethtool_get_settings,
9174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka};
9184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9190fc0b732eaa38beb93a6fb62f77c7bd9622c76ecStephen Hemmingerstatic const struct ethtool_ops qeth_l2_osn_ops = {
9204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.get_strings = qeth_core_get_strings,
9214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.get_ethtool_stats = qeth_core_get_ethtool_stats,
922df8b4ec8b15a5db84706548149add3131c3af8baBen Hutchings	.get_sset_count = qeth_core_get_sset_count,
9234a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.get_drvinfo = qeth_core_get_drvinfo,
9244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka};
9254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9263d58cefd823e47209ffcac9cada0a618771da1a4Frank Blaschkastatic const struct net_device_ops qeth_l2_netdev_ops = {
9278403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_open		= qeth_l2_open,
9288403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_stop		= qeth_l2_stop,
9298403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_get_stats		= qeth_get_stats,
9308403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_start_xmit		= qeth_l2_hard_start_xmit,
9318403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_validate_addr	= eth_validate_addr,
932afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= qeth_l2_set_multicast_list,
9338403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_do_ioctl	   	= qeth_l2_do_ioctl,
9348403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_set_mac_address    = qeth_l2_set_mac_address,
9358403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_change_mtu	   	= qeth_change_mtu,
9368403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_vlan_rx_add_vid	= qeth_l2_vlan_rx_add_vid,
9378403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_vlan_rx_kill_vid   = qeth_l2_vlan_rx_kill_vid,
9388403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	.ndo_tx_timeout	   	= qeth_tx_timeout,
9398403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka};
9408403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka
9414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_setup_netdev(struct qeth_card *card)
9424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
9434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	switch (card->info.type) {
9444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	case QETH_CARD_TYPE_IQD:
9454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->dev = alloc_netdev(0, "hsi%d", ether_setup);
9464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		break;
9474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	case QETH_CARD_TYPE_OSN:
9484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->dev = alloc_netdev(0, "osn%d", ether_setup);
9494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->dev->flags |= IFF_NOARP;
9504a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		break;
9514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	default:
9524a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->dev = alloc_etherdev(0);
9534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
9544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!card->dev)
9564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
9574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
958509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	card->dev->ml_priv = card;
9594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
9604a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->dev->mtu = card->info.initial_mtu;
9618403b13c7627df7104e450cbc845627bf25c8cd6Frank Blaschka	card->dev->netdev_ops = &qeth_l2_netdev_ops;
9624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->info.type != QETH_CARD_TYPE_OSN)
9634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		SET_ETHTOOL_OPS(card->dev, &qeth_l2_ethtool_ops);
9644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	else
9654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		SET_ETHTOOL_OPS(card->dev, &qeth_l2_osn_ops);
9664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->dev->features |= NETIF_F_HW_VLAN_FILTER;
9674a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->info.broadcast_capable = 1;
9684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_l2_request_initial_mac(card);
9694a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	SET_NETDEV_DEV(card->dev, &card->gdev->dev);
970a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT);
9714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return register_netdev(card->dev);
9724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
9734a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
9754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
9764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
9774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
9784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	enum qeth_card_states recover_flag;
9794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	BUG_ON(!card);
9819dc48ccc68b9dfc01c2beee2d4317fb3df3fdce9Ursula Braun	mutex_lock(&card->discipline_mutex);
982c4949f074332a64baeb2ead6ab9319ca37642f96Frank Blaschka	mutex_lock(&card->conf_mutex);
983d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_TEXT(SETUP, 2, "setonlin");
984d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
9854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	recover_flag = card->state;
9874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = qeth_core_hardsetup_card(card);
9884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (rc) {
989d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann		QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
990aa90922479513db0d080239324d0d04701418ba5Ursula Braun		rc = -ENODEV;
9914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		goto out_remove;
9924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
9934a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
994aa90922479513db0d080239324d0d04701418ba5Ursula Braun	if (!card->dev && qeth_l2_setup_netdev(card)) {
995aa90922479513db0d080239324d0d04701418ba5Ursula Braun		rc = -ENODEV;
9964a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		goto out_remove;
997aa90922479513db0d080239324d0d04701418ba5Ursula Braun	}
9984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
9994a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->info.type != QETH_CARD_TYPE_OSN)
10004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_l2_send_setmac(card, &card->dev->dev_addr[0]);
10014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10021da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka	if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
10031da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka		if (card->info.hwtrap &&
10041da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka		    qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))
10051da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka			card->info.hwtrap = 0;
10061da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka	} else
10071da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka		card->info.hwtrap = 0;
10081da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka
10094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->state = CARD_STATE_HARDSETUP;
1010a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	memset(&card->rx, 0, sizeof(struct qeth_rx));
10114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_print_status_message(card);
10124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	/* softsetup */
1014d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_TEXT(SETUP, 2, "softsetp");
10154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10164a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = qeth_send_startlan(card);
10174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (rc) {
1018d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
10194a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (rc == 0xe080) {
102074eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka			dev_warn(&card->gdev->dev,
102174eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka				"The LAN is offline\n");
10224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			card->lan_online = 0;
10232b6203bb7d85e6a2ca2088b8684f30be70246ddfUrsula Braun			goto contin;
10244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
1025aa90922479513db0d080239324d0d04701418ba5Ursula Braun		rc = -ENODEV;
1026f214856540f6d704e817bf6b26a6bca9e697ee72Ursula Braun		goto out_remove;
10274a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	} else
10284a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->lan_online = 1;
10294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10302b6203bb7d85e6a2ca2088b8684f30be70246ddfUrsula Brauncontin:
10315113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	if ((card->info.type == QETH_CARD_TYPE_OSD) ||
10325113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	    (card->info.type == QETH_CARD_TYPE_OSX))
1033d64ecc22d0a4b175d97cb2b1e297a9c5e3bdb26dEinar Lueck		/* configure isolation level */
1034d64ecc22d0a4b175d97cb2b1e297a9c5e3bdb26dEinar Lueck		qeth_set_access_ctrl_online(card);
10355113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun
10365113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	if (card->info.type != QETH_CARD_TYPE_OSN &&
10375113fec0984276836cb6f0677f7cb53586ec3451Ursula Braun	    card->info.type != QETH_CARD_TYPE_OSM)
103870919e23ac35c9c244dfd73f97312894cae7d65fUrsula Braun		qeth_l2_process_vlans(card);
10394a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	netif_tx_disable(card->dev);
10414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = qeth_init_qdio_queues(card);
10434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (rc) {
1044d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann		QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
1045aa90922479513db0d080239324d0d04701418ba5Ursula Braun		rc = -ENODEV;
10464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		goto out_remove;
10474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
10484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->state = CARD_STATE_SOFTSETUP;
10492b6203bb7d85e6a2ca2088b8684f30be70246ddfUrsula Braun	if (card->lan_online)
10502b6203bb7d85e6a2ca2088b8684f30be70246ddfUrsula Braun		netif_carrier_on(card->dev);
10512b6203bb7d85e6a2ca2088b8684f30be70246ddfUrsula Braun	else
10522b6203bb7d85e6a2ca2088b8684f30be70246ddfUrsula Braun		netif_carrier_off(card->dev);
10534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_set_allowed_threads(card, 0xffffffff, 0);
10554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (recover_flag == CARD_STATE_RECOVER) {
10564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		if (recovery_mode &&
10574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		    card->info.type != QETH_CARD_TYPE_OSN) {
1058394234406c7a8a6b947d230b115c918c0a1def68Ursula Braun			__qeth_l2_open(card->dev);
10594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		} else {
10604a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			rtnl_lock();
10614a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			dev_open(card->dev);
10624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			rtnl_unlock();
10634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		}
10644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		/* this also sets saved unicast addresses */
10654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_l2_set_multicast_list(card->dev);
10664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
10674a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	/* let user_space know that device is online */
10684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
1069c4949f074332a64baeb2ead6ab9319ca37642f96Frank Blaschka	mutex_unlock(&card->conf_mutex);
10709dc48ccc68b9dfc01c2beee2d4317fb3df3fdce9Ursula Braun	mutex_unlock(&card->discipline_mutex);
10714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
1072aa90922479513db0d080239324d0d04701418ba5Ursula Braun
10734a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkaout_remove:
10744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_l2_stop_card(card, 0);
10754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	ccw_device_set_offline(CARD_DDEV(card));
10764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	ccw_device_set_offline(CARD_WDEV(card));
10774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	ccw_device_set_offline(CARD_RDEV(card));
10784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (recover_flag == CARD_STATE_RECOVER)
10794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->state = CARD_STATE_RECOVER;
10804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	else
10814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->state = CARD_STATE_DOWN;
1082c4949f074332a64baeb2ead6ab9319ca37642f96Frank Blaschka	mutex_unlock(&card->conf_mutex);
10839dc48ccc68b9dfc01c2beee2d4317fb3df3fdce9Ursula Braun	mutex_unlock(&card->discipline_mutex);
1084aa90922479513db0d080239324d0d04701418ba5Ursula Braun	return rc;
10854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
10864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_set_online(struct ccwgroup_device *gdev)
10884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
10894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return __qeth_l2_set_online(gdev, 0);
10904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
10914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
10934a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka					int recovery_mode)
10944a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
10954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
10964a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0, rc2 = 0, rc3 = 0;
10974a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	enum qeth_card_states recover_flag;
10984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
10999dc48ccc68b9dfc01c2beee2d4317fb3df3fdce9Ursula Braun	mutex_lock(&card->discipline_mutex);
1100c4949f074332a64baeb2ead6ab9319ca37642f96Frank Blaschka	mutex_lock(&card->conf_mutex);
1101d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_TEXT(SETUP, 3, "setoffl");
1102d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann	QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
11034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
11044a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (card->dev && netif_carrier_ok(card->dev))
11054a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		netif_carrier_off(card->dev);
11064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	recover_flag = card->state;
11071da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka	if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
11081da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka		qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
11091da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka		card->info.hwtrap = 1;
11101da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka	}
11110f5623c9ebfc6576c5682ab3b335c57812f6c87eUrsula Braun	qeth_l2_stop_card(card, recovery_mode);
11124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc  = ccw_device_set_offline(CARD_DDEV(card));
11134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc2 = ccw_device_set_offline(CARD_WDEV(card));
11144a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc3 = ccw_device_set_offline(CARD_RDEV(card));
11154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!rc)
11164a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		rc = (rc2) ? rc2 : rc3;
11174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (rc)
1118d11ba0c40fa8a21511822efee3be8389f94f0431Peter Tiedemann		QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
11194a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (recover_flag == CARD_STATE_UP)
11204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		card->state = CARD_STATE_RECOVER;
11214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	/* let user_space know that device is offline */
11224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
1123c4949f074332a64baeb2ead6ab9319ca37642f96Frank Blaschka	mutex_unlock(&card->conf_mutex);
11249dc48ccc68b9dfc01c2beee2d4317fb3df3fdce9Ursula Braun	mutex_unlock(&card->discipline_mutex);
11254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
11264a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
11274a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
11284a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_set_offline(struct ccwgroup_device *cgdev)
11294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
11304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return __qeth_l2_set_offline(cgdev, 0);
11314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
11324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
11334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_l2_recover(void *ptr)
11344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
11354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card;
11364a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
11374a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
11384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card = (struct qeth_card *) ptr;
1139847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "recover1");
11404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
11414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return 0;
1142847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "recover2");
114374eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka	dev_warn(&card->gdev->dev,
114474eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka		"A recovery process has been started for the device\n");
11454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	__qeth_l2_set_offline(card->gdev, 1);
11464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = __qeth_l2_set_online(card->gdev, 1);
11474a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!rc)
114874eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka		dev_info(&card->gdev->dev,
114974eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka			"Device successfully recovered!\n");
115028a7e4c906bd86419eb8572b3b1343e619cd1470Ursula Braun	else {
1151869da90b9ae39f0d5b9b5aa3a84502684a6aa1f4Ursula Braun		rtnl_lock();
1152869da90b9ae39f0d5b9b5aa3a84502684a6aa1f4Ursula Braun		dev_close(card->dev);
1153869da90b9ae39f0d5b9b5aa3a84502684a6aa1f4Ursula Braun		rtnl_unlock();
115474eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka		dev_warn(&card->gdev->dev, "The qeth device driver "
115574eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka			"failed to recover an error on the device\n");
115628a7e4c906bd86419eb8572b3b1343e619cd1470Ursula Braun	}
1157a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
1158a1c3ed4c9ca01dded8d511a1d1daf271fbae8d89Frank Blaschka	qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
11594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
11604a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
11614a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
11624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int __init qeth_l2_init(void)
11634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
116474eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka	pr_info("register layer 2 discipline\n");
11654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
11664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
11674a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
11684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic void __exit qeth_l2_exit(void)
11694a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
117074eacdb9c2bf9fc6e8c6785013b5dd0e551a9dfaFrank Blaschka	pr_info("unregister layer 2 discipline\n");
11714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
11724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
11734a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic void qeth_l2_shutdown(struct ccwgroup_device *gdev)
11744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
11754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
1176f78ac2bbb1580c2b62ae20d47aaa2ef255f54d38Ursula Braun	qeth_set_allowed_threads(card, 0, 1);
11771da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka	if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap)
11781da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka		qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
11794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_qdio_clear_card(card, 0);
11804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_clear_qdio_buffers(card);
11814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
11824a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1183bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschkastatic int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
1184bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka{
1185bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
1186bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka
1187bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	if (card->dev)
1188bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		netif_device_detach(card->dev);
1189bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	qeth_set_allowed_threads(card, 0, 1);
1190bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
1191bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	if (gdev->state == CCWGROUP_OFFLINE)
1192bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		return 0;
1193bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	if (card->state == CARD_STATE_UP) {
11941da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka		if (card->info.hwtrap)
11951da74b1c10062eff5f67accb3bcb27fa329a55d6Frank Blaschka			qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
1196bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		__qeth_l2_set_offline(card->gdev, 1);
1197bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	} else
1198bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		__qeth_l2_set_offline(card->gdev, 0);
1199bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	return 0;
1200bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka}
1201bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka
1202bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschkastatic int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
1203bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka{
1204bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
1205bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	int rc = 0;
1206bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka
1207bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	if (gdev->state == CCWGROUP_OFFLINE)
1208bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		goto out;
1209bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka
1210bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	if (card->state == CARD_STATE_RECOVER) {
1211bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		rc = __qeth_l2_set_online(card->gdev, 1);
1212bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		if (rc) {
1213869da90b9ae39f0d5b9b5aa3a84502684a6aa1f4Ursula Braun			rtnl_lock();
1214869da90b9ae39f0d5b9b5aa3a84502684a6aa1f4Ursula Braun			dev_close(card->dev);
1215869da90b9ae39f0d5b9b5aa3a84502684a6aa1f4Ursula Braun			rtnl_unlock();
1216bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		}
1217bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	} else
1218bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		rc = __qeth_l2_set_online(card->gdev, 0);
1219bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschkaout:
1220bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	qeth_set_allowed_threads(card, 0xffffffff, 0);
1221bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	if (card->dev)
1222bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		netif_device_attach(card->dev);
1223bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	if (rc)
1224bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka		dev_warn(&card->gdev->dev, "The qeth device driver "
1225bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka			"failed to recover an error on the device\n");
1226bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	return rc;
1227bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka}
1228bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka
12294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastruct ccwgroup_driver qeth_l2_ccwgroup_driver = {
12304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.probe = qeth_l2_probe_device,
12314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.remove = qeth_l2_remove_device,
12324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.set_online = qeth_l2_set_online,
12334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.set_offline = qeth_l2_set_offline,
12344a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	.shutdown = qeth_l2_shutdown,
1235bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	.freeze = qeth_l2_pm_suspend,
1236bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	.thaw = qeth_l2_pm_resume,
1237bbcfcdc8324e75532c4d2592a545a91fcb45f229Frank Blaschka	.restore = qeth_l2_pm_resume,
12384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka};
12394a71df50047f0db65ea09b1be155852e81a45ebaFrank BlaschkaEXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver);
12404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
12414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_osn_send_control_data(struct qeth_card *card, int len,
12424a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   struct qeth_cmd_buffer *iob)
12434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
12444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	unsigned long flags;
12454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc = 0;
12464a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1247847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 5, "osndctrd");
12484a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
12494a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	wait_event(card->wait_q,
12504a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		   atomic_cmpxchg(&card->write.irq_pending, 0, 1) == 0);
12514a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_prepare_control_data(card, len, iob);
1252847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 6, "osnoirqp");
12534a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
12544a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
12554a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			      (addr_t) iob, 0, 0);
12564a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
12574a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (rc) {
125814cc21b6770972e5d1487dbf3a2caaf63cae909aFrank Blaschka		QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
12594a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			   "ccw_device_start rc = %i\n", rc);
1260847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte		QETH_CARD_TEXT_(card, 2, " err%d", rc);
12614a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		qeth_release_buffer(iob->channel, iob);
12624a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		atomic_set(&card->write.irq_pending, 0);
12634a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		wake_up(&card->wait_q);
12644a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	}
12654a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return rc;
12664a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
12674a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
12684a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkastatic int qeth_osn_send_ipa_cmd(struct qeth_card *card,
12694a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka			struct qeth_cmd_buffer *iob, int data_len)
12704a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
12714a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	u16 s1, s2;
12724a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
1273847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 4, "osndipa");
12744a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
12754a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2);
12764a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len);
12774a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	s2 = (u16)data_len;
12784a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);
12794a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2);
12804a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2);
12814a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);
12824a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return qeth_osn_send_control_data(card, s1, iob);
12834a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
12844a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
12854a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkaint qeth_osn_assist(struct net_device *dev, void *data, int data_len)
12864a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
12874a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_cmd_buffer *iob;
12884a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card;
12894a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	int rc;
12904a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
12914a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!dev)
12924a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
1293509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	card = dev->ml_priv;
12944a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!card)
12954a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
1296847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "osnsdmc");
12974a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if ((card->state != CARD_STATE_UP) &&
12984a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	    (card->state != CARD_STATE_SOFTSETUP))
12994a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
13004a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	iob = qeth_wait_for_buffer(&card->write);
13014a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	memcpy(iob->data+IPA_PDU_HEADER_SIZE, data, data_len);
13024a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	rc = qeth_osn_send_ipa_cmd(card, iob, data_len);
13034a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return rc;
13044a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
13054a71df50047f0db65ea09b1be155852e81a45ebaFrank BlaschkaEXPORT_SYMBOL(qeth_osn_assist);
13064a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
13074a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkaint qeth_osn_register(unsigned char *read_dev_no, struct net_device **dev,
13084a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		  int (*assist_cb)(struct net_device *, void *),
13094a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		  int (*data_cb)(struct sk_buff *))
13104a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
13114a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card;
13124a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
13134a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	*dev = qeth_l2_netdev_by_devno(read_dev_no);
13144a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (*dev == NULL)
13154a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
1316509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	card = (*dev)->ml_priv;
13174a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!card)
13184a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -ENODEV;
1319847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "osnreg");
13204a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if ((assist_cb == NULL) || (data_cb == NULL))
13214a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return -EINVAL;
13224a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->osn_info.assist_cb = assist_cb;
13234a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->osn_info.data_cb = data_cb;
13244a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return 0;
13254a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
13264a71df50047f0db65ea09b1be155852e81a45ebaFrank BlaschkaEXPORT_SYMBOL(qeth_osn_register);
13274a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
13284a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkavoid qeth_osn_deregister(struct net_device *dev)
13294a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka{
13304a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	struct qeth_card *card;
13314a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
13324a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!dev)
13334a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return;
1334509e2562adfd63964aa30c1ddd9ddf4e57949351Heiko Carstens	card = dev->ml_priv;
13354a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	if (!card)
13364a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka		return;
1337847a50fd9f3d6a1ee8c8bf646aa8c9a61ea51550Carsten Otte	QETH_CARD_TEXT(card, 2, "osndereg");
13384a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->osn_info.assist_cb = NULL;
13394a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	card->osn_info.data_cb = NULL;
13404a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka	return;
13414a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka}
13424a71df50047f0db65ea09b1be155852e81a45ebaFrank BlaschkaEXPORT_SYMBOL(qeth_osn_deregister);
13434a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschka
13444a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkamodule_init(qeth_l2_init);
13454a71df50047f0db65ea09b1be155852e81a45ebaFrank Blaschkamodule_exit(qeth_l2_exit);
13464a71df50047f0db65ea09b1be155852e81a45ebaFrank BlaschkaMODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
13474a71df50047f0db65ea09b1be155852e81a45ebaFrank BlaschkaMODULE_DESCRIPTION("qeth layer 2 discipline");
13484a71df50047f0db65ea09b1be155852e81a45ebaFrank BlaschkaMODULE_LICENSE("GPL");
1349