aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/Kconfig1
-rw-r--r--drivers/s390/block/dasd.c12
-rw-r--r--drivers/s390/block/dasd_eckd.c7
-rw-r--r--drivers/s390/block/dasd_eer.c6
-rw-r--r--drivers/s390/block/dcssblk.c3
-rw-r--r--drivers/s390/char/Makefile2
-rw-r--r--drivers/s390/char/monreader.c6
-rw-r--r--drivers/s390/char/sclp_early.c3
-rw-r--r--drivers/s390/char/sclp_early_core.c4
-rw-r--r--drivers/s390/cio/chp.c10
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/cmf.c15
-rw-r--r--drivers/s390/cio/css.c8
-rw-r--r--drivers/s390/cio/device.c10
-rw-r--r--drivers/s390/cio/itcw.c2
-rw-r--r--drivers/s390/cio/qdio_main.c4
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c2
-rw-r--r--drivers/s390/crypto/ap_card.c2
-rw-r--r--drivers/s390/net/Kconfig3
-rw-r--r--drivers/s390/net/lcs.c10
-rw-r--r--drivers/s390/net/lcs.h3
-rw-r--r--drivers/s390/net/qeth_core.h49
-rw-r--r--drivers/s390/net/qeth_core_main.c119
-rw-r--r--drivers/s390/net/qeth_core_mpc.h13
-rw-r--r--drivers/s390/net/qeth_l2.h3
-rw-r--r--drivers/s390/net/qeth_l2_main.c92
-rw-r--r--drivers/s390/net/qeth_l3.h15
-rw-r--r--drivers/s390/net/qeth_l3_main.c510
-rw-r--r--drivers/s390/net/qeth_l3_sys.c114
-rw-r--r--drivers/s390/virtio/virtio_ccw.c29
30 files changed, 457 insertions, 602 deletions
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index bc27d716aa6b..1444333210c7 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -16,6 +16,7 @@ config BLK_DEV_XPRAM
config DCSSBLK
def_tristate m
select DAX
+ select FS_DAX_LIMITED
prompt "DCSSBLK support"
depends on S390 && BLOCK
help
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index d4e8dff673cc..a7c15f0085e2 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1393,10 +1393,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
DBF_DEV_EVENT(DBF_ERR, device, "%s",
"device gone, retry");
break;
- case -EIO:
- DBF_DEV_EVENT(DBF_ERR, device, "%s",
- "I/O error, retry");
- break;
case -EINVAL:
/*
* device not valid so no I/O could be running
@@ -1412,10 +1408,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
/* fake rc to success */
rc = 0;
break;
- case -EBUSY:
- DBF_DEV_EVENT(DBF_ERR, device, "%s",
- "device busy, retry later");
- break;
default:
/* internal error 10 - unknown rc*/
snprintf(errorstring, ERRORLENGTH, "10 %d", rc);
@@ -1489,10 +1481,6 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
"start_IO: device busy, retry later");
break;
- case -ETIMEDOUT:
- DBF_DEV_EVENT(DBF_WARNING, device, "%s",
- "start_IO: request timeout, retry later");
- break;
case -EACCES:
/* -EACCES indicates that the request used only a subset of the
* available paths and all these paths are gone. If the lpm of
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index a2edf2a7ace9..29397a9dba68 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -5231,7 +5231,7 @@ static int dasd_hosts_print(struct dasd_device *device, struct seq_file *m)
struct dasd_ckd_path_group_entry *entry;
struct dasd_ckd_host_information *info;
char sysplex[9] = "";
- int rc, i, j;
+ int rc, i;
access = kzalloc(sizeof(*access), GFP_NOIO);
if (!access) {
@@ -5251,10 +5251,7 @@ static int dasd_hosts_print(struct dasd_device *device, struct seq_file *m)
entry = (struct dasd_ckd_path_group_entry *)
(info->entry + i * info->entry_size);
/* PGID */
- seq_puts(m, "pgid ");
- for (j = 0; j < 11; j++)
- seq_printf(m, "%02x", entry->pgid[j]);
- seq_putc(m, '\n');
+ seq_printf(m, "pgid %*phN\n", 11, entry->pgid);
/* FLAGS */
seq_printf(m, "status_flags %02x\n", entry->status_flags);
/* SYSPLEX NAME */
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index a7917d473774..fb2c3599d95c 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -661,9 +661,9 @@ static ssize_t dasd_eer_read(struct file *filp, char __user *buf,
return effective_count;
}
-static unsigned int dasd_eer_poll(struct file *filp, poll_table *ptable)
+static __poll_t dasd_eer_poll(struct file *filp, poll_table *ptable)
{
- unsigned int mask;
+ __poll_t mask;
unsigned long flags;
struct eerbuffer *eerb;
@@ -671,7 +671,7 @@ static unsigned int dasd_eer_poll(struct file *filp, poll_table *ptable)
poll_wait(filp, &dasd_eer_read_wait_queue, ptable);
spin_lock_irqsave(&bufferlock, flags);
if (eerb->head != eerb->tail)
- mask = POLLIN | POLLRDNORM ;
+ mask = EPOLLIN | EPOLLRDNORM ;
else
mask = 0;
spin_unlock_irqrestore(&bufferlock, flags);
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 6aaefb780436..9cae08b36b80 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -916,7 +916,8 @@ __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff,
dev_sz = dev_info->end - dev_info->start + 1;
*kaddr = (void *) dev_info->start + offset;
- *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV);
+ *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset),
+ PFN_DEV|PFN_SPECIAL);
return (dev_sz - offset) / PAGE_SIZE;
}
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 614b44e70a28..a2b33a22c82a 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -19,6 +19,8 @@ endif
CFLAGS_sclp_early_core.o += -D__NO_FORTIFY
+CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE)
+
obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
sclp_early.o sclp_early_core.o
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index bf4ab4efed73..7bc616b253f1 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -429,15 +429,15 @@ out_copy:
return count;
}
-static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p)
+static __poll_t mon_poll(struct file *filp, struct poll_table_struct *p)
{
struct mon_private *monpriv = filp->private_data;
poll_wait(filp, &mon_read_wait_queue, p);
if (unlikely(atomic_read(&monpriv->iucv_severed)))
- return POLLERR;
+ return EPOLLERR;
if (atomic_read(&monpriv->read_ready))
- return POLLIN | POLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM;
return 0;
}
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index d06bc5674e5f..6b1891539c84 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -49,7 +49,7 @@ struct read_info_sccb {
u8 _pad_112[116 - 112]; /* 112-115 */
u8 fac116; /* 116 */
u8 fac117; /* 117 */
- u8 _pad_118; /* 118 */
+ u8 fac118; /* 118 */
u8 fac119; /* 119 */
u16 hcpua; /* 120-121 */
u8 _pad_122[124 - 122]; /* 122-123 */
@@ -100,6 +100,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp.has_esca = !!(sccb->fac116 & 0x08);
sclp.has_pfmfi = !!(sccb->fac117 & 0x40);
sclp.has_ibs = !!(sccb->fac117 & 0x20);
+ sclp.has_gisaf = !!(sccb->fac118 & 0x08);
sclp.has_hvs = !!(sccb->fac119 & 0x80);
sclp.has_kss = !!(sccb->fac98 & 0x01);
if (sccb->fac85 & 0x02)
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c
index edeb2597b0b8..17b0c67f3e8d 100644
--- a/drivers/s390/char/sclp_early_core.c
+++ b/drivers/s390/char/sclp_early_core.c
@@ -12,8 +12,8 @@
#include "sclp.h"
#include "sclp_rw.h"
-char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(data);
-int sclp_init_state __section(data) = sclp_init_state_uninitialized;
+char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data);
+int sclp_init_state __section(.data) = sclp_init_state_uninitialized;
void sclp_early_wait_irq(void)
{
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 5c94a3aec4dd..f95b452b8bbc 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -412,7 +412,7 @@ static void chp_release(struct device *dev)
/**
* chp_update_desc - update channel-path description
- * @chp - channel-path
+ * @chp: channel-path
*
* Update the channel-path description of the specified channel-path
* including channel measurement related information.
@@ -438,7 +438,7 @@ int chp_update_desc(struct channel_path *chp)
/**
* chp_new - register a new channel-path
- * @chpid - channel-path ID
+ * @chpid: channel-path ID
*
* Create and register data structure representing new channel-path. Return
* zero on success, non-zero otherwise.
@@ -730,8 +730,8 @@ static void cfg_func(struct work_struct *work)
/**
* chp_cfg_schedule - schedule chpid configuration request
- * @chpid - channel-path ID
- * @configure - Non-zero for configure, zero for deconfigure
+ * @chpid: channel-path ID
+ * @configure: Non-zero for configure, zero for deconfigure
*
* Schedule a channel-path configuration/deconfiguration request.
*/
@@ -747,7 +747,7 @@ void chp_cfg_schedule(struct chp_id chpid, int configure)
/**
* chp_cfg_cancel_deconfigure - cancel chpid deconfiguration request
- * @chpid - channel-path ID
+ * @chpid: channel-path ID
*
* Cancel an active channel-path deconfiguration request if it has not yet
* been performed.
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 987bf9a8c9f7..6886b3d34cf8 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -1059,7 +1059,7 @@ EXPORT_SYMBOL_GPL(cio_tm_start_key);
/**
* cio_tm_intrg - perform interrogate function
- * @sch - subchannel on which to perform the interrogate function
+ * @sch: subchannel on which to perform the interrogate function
*
* If the specified subchannel is running in transport-mode, perform the
* interrogate function. Return zero on success, non-zero otherwie.
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 5e495c62cfa7..8af4948dae80 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1118,9 +1118,10 @@ int ccw_set_cmf(struct ccw_device *cdev, int enable)
* enable_cmf() - switch on the channel measurement for a specific device
* @cdev: The ccw device to be enabled
*
- * Returns %0 for success or a negative error value.
- * Note: If this is called on a device for which channel measurement is already
- * enabled a reset of the measurement data is triggered.
+ * Enable channel measurements for @cdev. If this is called on a device
+ * for which channel measurement is already enabled a reset of the
+ * measurement data is triggered.
+ * Returns: %0 for success or a negative error value.
* Context:
* non-atomic
*/
@@ -1160,7 +1161,7 @@ out_unlock:
* __disable_cmf() - switch off the channel measurement for a specific device
* @cdev: The ccw device to be disabled
*
- * Returns %0 for success or a negative error value.
+ * Returns: %0 for success or a negative error value.
*
* Context:
* non-atomic, device_lock() held.
@@ -1184,7 +1185,7 @@ int __disable_cmf(struct ccw_device *cdev)
* disable_cmf() - switch off the channel measurement for a specific device
* @cdev: The ccw device to be disabled
*
- * Returns %0 for success or a negative error value.
+ * Returns: %0 for success or a negative error value.
*
* Context:
* non-atomic
@@ -1205,7 +1206,7 @@ int disable_cmf(struct ccw_device *cdev)
* @cdev: the channel to be read
* @index: the index of the value to be read
*
- * Returns the value read or %0 if the value cannot be read.
+ * Returns: The value read or %0 if the value cannot be read.
*
* Context:
* any
@@ -1220,7 +1221,7 @@ u64 cmf_read(struct ccw_device *cdev, int index)
* @cdev: the channel to be read
* @data: a pointer to a data block that will be filled
*
- * Returns %0 on success, a negative error value otherwise.
+ * Returns: %0 on success, a negative error value otherwise.
*
* Context:
* any
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 0f11dce6e224..9263a0fb3858 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -268,7 +268,7 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%01x\n", sch->st);
}
-static DEVICE_ATTR(type, 0444, type_show, NULL);
+static DEVICE_ATTR_RO(type);
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -278,7 +278,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "css:t%01X\n", sch->st);
}
-static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
+static DEVICE_ATTR_RO(modalias);
static struct attribute *subch_attrs[] = {
&dev_attr_type.attr,
@@ -315,7 +315,7 @@ static ssize_t chpids_show(struct device *dev,
ret += sprintf(buf + ret, "\n");
return ret;
}
-static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
+static DEVICE_ATTR_RO(chpids);
static ssize_t pimpampom_show(struct device *dev,
struct device_attribute *attr,
@@ -327,7 +327,7 @@ static ssize_t pimpampom_show(struct device *dev,
return sprintf(buf, "%02x %02x %02x\n",
pmcw->pim, pmcw->pam, pmcw->pom);
}
-static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
+static DEVICE_ATTR_RO(pimpampom);
static struct attribute *io_subchannel_type_attrs[] = {
&dev_attr_chpids.attr,
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 75a245f38e2e..f50ea035aa9b 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -597,13 +597,13 @@ static ssize_t vpm_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%02x\n", sch->vpm);
}
-static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
-static DEVICE_ATTR(cutype, 0444, cutype_show, NULL);
-static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
-static DEVICE_ATTR(online, 0644, online_show, online_store);
+static DEVICE_ATTR_RO(devtype);
+static DEVICE_ATTR_RO(cutype);
+static DEVICE_ATTR_RO(modalias);
+static DEVICE_ATTR_RW(online);
static DEVICE_ATTR(availability, 0444, available_show, NULL);
static DEVICE_ATTR(logging, 0200, NULL, initiate_logging);
-static DEVICE_ATTR(vpm, 0444, vpm_show, NULL);
+static DEVICE_ATTR_RO(vpm);
static struct attribute *io_subchannel_attrs[] = {
&dev_attr_logging.attr,
diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c
index deaf59f93326..19e46363348c 100644
--- a/drivers/s390/cio/itcw.c
+++ b/drivers/s390/cio/itcw.c
@@ -15,7 +15,7 @@
#include <asm/fcx.h>
#include <asm/itcw.h>
-/**
+/*
* struct itcw - incremental tcw helper data type
*
* This structure serves as a handle for the incremental construction of a
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 95b0efe28afb..d5b02de02a3a 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -72,6 +72,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
* @mask: which output queues to process
* @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer
* @fc: function code to perform
+ * @aob: asynchronous operation block
*
* Returns condition code.
* Note: For IQDC unicast queues only the highest priority queue is processed.
@@ -1761,9 +1762,6 @@ EXPORT_SYMBOL(qdio_stop_irq);
* @response: Response code will be stored at this address
* @cb: Callback function will be executed for each element
* of the address list
- * @priv: Pointer passed from the caller to qdio_pnso_brinfo()
- * @type: Type of the address entry passed to the callback
- * @entry: Entry containg the address of the specified type
* @priv: Pointer to pass to the callback function.
*
* Performs "Store-network-bridging-information list" operation and calls
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index d9a2fffd034b..2c7550797ec2 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -835,7 +835,7 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
/**
* cp_iova_pinned() - check if an iova is pinned for a ccw chain.
- * @cmd: ccwchain command on which to perform the operation
+ * @cp: channel_program on which to perform the operation
* @iova: the iova to check
*
* If the @iova is currently pinned for the ccw chain, return true;
diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c
index 97a8cf578116..2c726df210f6 100644
--- a/drivers/s390/crypto/ap_card.c
+++ b/drivers/s390/crypto/ap_card.c
@@ -57,7 +57,7 @@ static ssize_t ap_functions_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions);
}
-static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL);
+static DEVICE_ATTR_RO(ap_functions);
static ssize_t ap_req_count_show(struct device *dev,
struct device_attribute *attr,
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index a782a207ad31..c7e484f70654 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -91,9 +91,6 @@ config QETH_L3
To compile as a module choose M. The module name is qeth_l3.
If unsure, choose Y.
-config QETH_IPV6
- def_bool y if (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y')
-
config CCWGROUP
tristate
default (LCS || CTCM || QETH)
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 92ae84a927fc..0ee8f33efb54 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -756,18 +756,14 @@ lcs_get_lancmd(struct lcs_card *card, int count)
static void
lcs_get_reply(struct lcs_reply *reply)
{
- WARN_ON(atomic_read(&reply->refcnt) <= 0);
- atomic_inc(&reply->refcnt);
+ refcount_inc(&reply->refcnt);
}
static void
lcs_put_reply(struct lcs_reply *reply)
{
- WARN_ON(atomic_read(&reply->refcnt) <= 0);
- if (atomic_dec_and_test(&reply->refcnt)) {
+ if (refcount_dec_and_test(&reply->refcnt))
kfree(reply);
- }
-
}
static struct lcs_reply *
@@ -780,7 +776,7 @@ lcs_alloc_reply(struct lcs_cmd *cmd)
reply = kzalloc(sizeof(struct lcs_reply), GFP_ATOMIC);
if (!reply)
return NULL;
- atomic_set(&reply->refcnt,1);
+ refcount_set(&reply->refcnt, 1);
reply->sequence_no = cmd->sequence_no;
reply->received = 0;
reply->rc = 0;
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h
index fbc8b90b1f85..bd52caa3b11b 100644
--- a/drivers/s390/net/lcs.h
+++ b/drivers/s390/net/lcs.h
@@ -5,6 +5,7 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
+#include <linux/refcount.h>
#include <asm/ccwdev.h>
#define LCS_DBF_TEXT(level, name, text) \
@@ -271,7 +272,7 @@ struct lcs_buffer {
struct lcs_reply {
struct list_head list;
__u16 sequence_no;
- atomic_t refcnt;
+ refcount_t refcnt;
/* Callback for completion notification. */
void (*callback)(struct lcs_card *, struct lcs_cmd *);
wait_queue_head_t wait_q;
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index badf42acbf95..959c65cf75d9 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -21,6 +21,7 @@
#include <linux/ethtool.h>
#include <linux/hashtable.h>
#include <linux/ip.h>
+#include <linux/refcount.h>
#include <net/ipv6.h>
#include <net/if_inet6.h>
@@ -296,8 +297,23 @@ struct qeth_hdr_layer3 {
__u8 ext_flags;
__u16 vlan_id;
__u16 frame_offset;
- __u8 dest_addr[16];
-} __attribute__ ((packed));
+ union {
+ /* TX: */
+ u8 ipv6_addr[16];
+ struct ipv4 {
+ u8 res[12];
+ u32 addr;
+ } ipv4;
+ /* RX: */
+ struct rx {
+ u8 res1[2];
+ u8 src_mac[6];
+ u8 res2[4];
+ u16 vlan_id;
+ u8 res3[2];
+ } rx;
+ } next_hop;
+};
struct qeth_hdr_layer2 {
__u8 id;
@@ -504,12 +520,6 @@ struct qeth_qdio_info {
int default_out_queue;
};
-#define QETH_ETH_MAC_V4 0x0100 /* like v4 */
-#define QETH_ETH_MAC_V6 0x3333 /* like v6 */
-/* tr mc mac is longer, but that will be enough to detect mc frames */
-#define QETH_TR_MAC_NC 0xc000 /* non-canonical */
-#define QETH_TR_MAC_C 0x0300 /* canonical */
-
/**
* buffer stuff for read channel
*/
@@ -581,6 +591,11 @@ struct qeth_cmd_buffer {
void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *);
};
+static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
+{
+ return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
+}
+
/**
* definition of a qeth channel, used for read and write
*/
@@ -632,7 +647,7 @@ struct qeth_reply {
int rc;
void *param;
struct qeth_card *card;
- atomic_t refcnt;
+ refcount_t refcnt;
};
struct qeth_card_blkt {
@@ -836,7 +851,7 @@ struct qeth_trap_id {
*/
static inline int qeth_get_elements_for_range(addr_t start, addr_t end)
{
- return PFN_UP(end - 1) - PFN_DOWN(start);
+ return PFN_UP(end) - PFN_DOWN(start);
}
static inline int qeth_get_micros(void)
@@ -846,14 +861,16 @@ static inline int qeth_get_micros(void)
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
- __be16 *p = &((struct ethhdr *)skb->data)->h_proto;
+ struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
+ __be16 prot = veth->h_vlan_proto;
+
+ if (prot == htons(ETH_P_8021Q))
+ prot = veth->h_vlan_encapsulated_proto;
- if (be16_to_cpu(*p) == ETH_P_8021Q)
- p += 2;
- switch (be16_to_cpu(*p)) {
- case ETH_P_IPV6:
+ switch (prot) {
+ case htons(ETH_P_IPV6):
return 6;
- case ETH_P_IP:
+ case htons(ETH_P_IP):
return 4;
default:
return 0;
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 3614df68830f..ca72f3311004 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -36,6 +36,7 @@
#include <asm/diag.h>
#include <asm/cio.h>
#include <asm/ccwdev.h>
+#include <asm/cpcmd.h>
#include "qeth_core.h"
@@ -564,7 +565,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
if (reply) {
- atomic_set(&reply->refcnt, 1);
+ refcount_set(&reply->refcnt, 1);
atomic_set(&reply->received, 0);
reply->card = card;
}
@@ -573,14 +574,12 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
static void qeth_get_reply(struct qeth_reply *reply)
{
- WARN_ON(atomic_read(&reply->refcnt) <= 0);
- atomic_inc(&reply->refcnt);
+ refcount_inc(&reply->refcnt);
}
static void qeth_put_reply(struct qeth_reply *reply)
{
- WARN_ON(atomic_read(&reply->refcnt) <= 0);
- if (atomic_dec_and_test(&reply->refcnt))
+ if (refcount_dec_and_test(&reply->refcnt))
kfree(reply);
}
@@ -1717,23 +1716,87 @@ static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd)
(prcd[0x11] == _ascebc['M']));
}
+static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card)
+{
+ enum qeth_discipline_id disc = QETH_DISCIPLINE_UNDETERMINED;
+ struct diag26c_vnic_resp *response = NULL;
+ struct diag26c_vnic_req *request = NULL;
+ struct ccw_dev_id id;
+ char userid[80];
+ int rc = 0;
+
+ QETH_DBF_TEXT(SETUP, 2, "vmlayer");
+
+ cpcmd("QUERY USERID", userid, sizeof(userid), &rc);
+ if (rc)
+ goto out;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL | GFP_DMA);
+ response = kzalloc(sizeof(*response), GFP_KERNEL | GFP_DMA);
+ if (!request || !response) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ ccw_device_get_id(CARD_RDEV(card), &id);
+ request->resp_buf_len = sizeof(*response);
+ request->resp_version = DIAG26C_VERSION6_VM65918;
+ request->req_format = DIAG26C_VNIC_INFO;
+ ASCEBC(userid, 8);
+ memcpy(&request->sys_name, userid, 8);
+ request->devno = id.devno;
+
+ QETH_DBF_HEX(CTRL, 2, request, sizeof(*request));
+ rc = diag26c(request, response, DIAG26C_PORT_VNIC);
+ QETH_DBF_HEX(CTRL, 2, request, sizeof(*request));
+ if (rc)
+ goto out;
+ QETH_DBF_HEX(CTRL, 2, response, sizeof(*response));
+
+ if (request->resp_buf_len < sizeof(*response) ||
+ response->version != request->resp_version) {
+ rc = -EIO;
+ goto out;
+ }
+
+ if (response->protocol == VNIC_INFO_PROT_L2)
+ disc = QETH_DISCIPLINE_LAYER2;
+ else if (response->protocol == VNIC_INFO_PROT_L3)
+ disc = QETH_DISCIPLINE_LAYER3;
+
+out:
+ kfree(response);
+ kfree(request);
+ if (rc)
+ QETH_DBF_TEXT_(SETUP, 2, "err%x", rc);
+ return disc;
+}
+
/* Determine whether the device requires a specific layer discipline */
static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card)
{
+ enum qeth_discipline_id disc = QETH_DISCIPLINE_UNDETERMINED;
+
if (card->info.type == QETH_CARD_TYPE_OSM ||
- card->info.type == QETH_CARD_TYPE_OSN) {
+ card->info.type == QETH_CARD_TYPE_OSN)
+ disc = QETH_DISCIPLINE_LAYER2;
+ else if (card->info.guestlan)
+ disc = (card->info.type == QETH_CARD_TYPE_IQD) ?
+ QETH_DISCIPLINE_LAYER3 :
+ qeth_vm_detect_layer(card);
+
+ switch (disc) {
+ case QETH_DISCIPLINE_LAYER2:
QETH_DBF_TEXT(SETUP, 3, "force l2");
- return QETH_DISCIPLINE_LAYER2;
- }
-
- /* virtual HiperSocket is L3 only: */
- if (card->info.guestlan && card->info.type == QETH_CARD_TYPE_IQD) {
+ break;
+ case QETH_DISCIPLINE_LAYER3:
QETH_DBF_TEXT(SETUP, 3, "force l3");
- return QETH_DISCIPLINE_LAYER3;
+ break;
+ default:
+ QETH_DBF_TEXT(SETUP, 3, "force no");
}
- QETH_DBF_TEXT(SETUP, 3, "force no");
- return QETH_DISCIPLINE_UNDETERMINED;
+ return disc;
}
static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd)
@@ -2057,7 +2120,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
unsigned long flags;
struct qeth_reply *reply = NULL;
unsigned long timeout, event_timeout;
- struct qeth_ipa_cmd *cmd;
+ struct qeth_ipa_cmd *cmd = NULL;
QETH_CARD_TEXT(card, 2, "sendctl");
@@ -2083,10 +2146,13 @@ int qeth_send_control_data(struct qeth_card *card, int len,
while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
qeth_prepare_control_data(card, len, iob);
- if (IS_IPA(iob->data))
+ if (IS_IPA(iob->data)) {
+ cmd = __ipa_cmd(iob);
event_timeout = QETH_IPA_TIMEOUT;
- else
+ } else {
event_timeout = QETH_TIMEOUT;
+ }
+
timeout = jiffies + event_timeout;
QETH_CARD_TEXT(card, 6, "noirqpnd");
@@ -2111,9 +2177,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
/* we have only one long running ipassist, since we can ensure
process context of this command we can sleep */
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- if ((cmd->hdr.command == IPA_CMD_SETIP) &&
- (cmd->hdr.prot_version == QETH_PROT_IPV4)) {
+ if (cmd && cmd->hdr.command == IPA_CMD_SETIP &&
+ cmd->hdr.prot_version == QETH_PROT_IPV4) {
if (!wait_event_timeout(reply->wait_q,
atomic_read(&reply->received), event_timeout))
goto time_err;
@@ -4218,9 +4283,8 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
if (!card->options.layer2 ||
!(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
- memcpy(card->dev->dev_addr,
- &cmd->data.setadapterparms.data.change_addr.addr,
- OSA_ADDR_LEN);
+ ether_addr_copy(card->dev->dev_addr,
+ cmd->data.setadapterparms.data.change_addr.addr);
card->info.mac_bits |= QETH_LAYER2_MAC_READ;
}
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
@@ -4242,9 +4306,9 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card)
return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC;
- cmd->data.setadapterparms.data.change_addr.addr_size = OSA_ADDR_LEN;
- memcpy(&cmd->data.setadapterparms.data.change_addr.addr,
- card->dev->dev_addr, OSA_ADDR_LEN);
+ cmd->data.setadapterparms.data.change_addr.addr_size = ETH_ALEN;
+ ether_addr_copy(cmd->data.setadapterparms.data.change_addr.addr,
+ card->dev->dev_addr);
rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_change_macaddr_cb,
NULL);
return rc;
@@ -4789,9 +4853,12 @@ int qeth_vm_request_mac(struct qeth_card *card)
request->op_code = DIAG26C_GET_MAC;
request->devno = id.devno;
+ QETH_DBF_HEX(CTRL, 2, request, sizeof(*request));
rc = diag26c(request, response, DIAG26C_MAC_SERVICES);
+ QETH_DBF_HEX(CTRL, 2, request, sizeof(*request));
if (rc)
goto out;
+ QETH_DBF_HEX(CTRL, 2, response, sizeof(*response));
if (request->resp_buf_len < sizeof(*response) ||
response->version != request->resp_version) {
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index ff6877f7b6f8..619f897b4bb0 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -10,6 +10,7 @@
#define __QETH_CORE_MPC_H__
#include <asm/qeth.h>
+#include <uapi/linux/if_ether.h>
#define IPA_PDU_HEADER_SIZE 0x40
#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer + 0x0e)
@@ -25,7 +26,6 @@ extern unsigned char IPA_PDU_HEADER[];
#define QETH_SEQ_NO_LENGTH 4
#define QETH_MPC_TOKEN_LENGTH 4
#define QETH_MCL_LENGTH 4
-#define OSA_ADDR_LEN 6
#define QETH_TIMEOUT (10 * HZ)
#define QETH_IPA_TIMEOUT (45 * HZ)
@@ -416,12 +416,11 @@ struct qeth_query_cmds_supp {
} __attribute__ ((packed));
struct qeth_change_addr {
- __u32 cmd;
- __u32 addr_size;
- __u32 no_macs;
- __u8 addr[OSA_ADDR_LEN];
-} __attribute__ ((packed));
-
+ u32 cmd;
+ u32 addr_size;
+ u32 no_macs;
+ u8 addr[ETH_ALEN];
+};
struct qeth_snmp_cmd {
__u8 token[16];
diff --git a/drivers/s390/net/qeth_l2.h b/drivers/s390/net/qeth_l2.h
index 09b1c4ef3dc9..f2130051ca11 100644
--- a/drivers/s390/net/qeth_l2.h
+++ b/drivers/s390/net/qeth_l2.h
@@ -22,8 +22,7 @@ int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout);
bool qeth_l2_vnicc_is_in_use(struct qeth_card *card);
struct qeth_mac {
- u8 mac_addr[OSA_ADDR_LEN];
- u8 is_uc:1;
+ u8 mac_addr[ETH_ALEN];
u8 disp_flag:2;
struct hlist_node hnode;
};
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 5863ea170ff2..7f236440483f 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -109,8 +109,8 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
if (!iob)
return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- cmd->data.setdelmac.mac_length = OSA_ADDR_LEN;
- memcpy(&cmd->data.setdelmac.mac, mac, OSA_ADDR_LEN);
+ cmd->data.setdelmac.mac_length = ETH_ALEN;
+ ether_addr_copy(cmd->data.setdelmac.mac, mac);
return qeth_setdelmac_makerc(card, qeth_send_ipa_cmd(card, iob,
NULL, NULL));
}
@@ -123,7 +123,7 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
if (rc == 0) {
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
- memcpy(card->dev->dev_addr, mac, OSA_ADDR_LEN);
+ ether_addr_copy(card->dev->dev_addr, mac);
dev_info(&card->gdev->dev,
"MAC address %pM successfully registered on device %s\n",
card->dev->dev_addr, card->dev->name);
@@ -156,54 +156,37 @@ static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
return rc;
}
-static int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac)
+static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
{
+ enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
+ IPA_CMD_SETGMAC : IPA_CMD_SETVMAC;
int rc;
- QETH_CARD_TEXT(card, 2, "L2Sgmac");
- rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC);
+ QETH_CARD_TEXT(card, 2, "L2Wmac");
+ rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc == -EEXIST)
- QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s\n",
- mac, QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(2, "MAC %pM already registered on %s\n",
+ mac, QETH_CARD_IFNAME(card));
else if (rc)
- QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %d\n",
- mac, QETH_CARD_IFNAME(card), rc);
+ QETH_DBF_MESSAGE(2, "Failed to register MAC %pM on %s: %d\n",
+ mac, QETH_CARD_IFNAME(card), rc);
return rc;
}
-static int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac)
+static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac)
{
+ enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
+ IPA_CMD_DELGMAC : IPA_CMD_DELVMAC;
int rc;
- QETH_CARD_TEXT(card, 2, "L2Dgmac");
- rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC);
+ QETH_CARD_TEXT(card, 2, "L2Rmac");
+ rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc)
- QETH_DBF_MESSAGE(2,
- "Could not delete group MAC %pM on %s: %d\n",
- mac, QETH_CARD_IFNAME(card), rc);
+ QETH_DBF_MESSAGE(2, "Failed to delete MAC %pM on %s: %d\n",
+ mac, QETH_CARD_IFNAME(card), rc);
return rc;
}
-static int qeth_l2_write_mac(struct qeth_card *card, struct qeth_mac *mac)
-{
- if (mac->is_uc) {
- return qeth_l2_send_setdelmac(card, mac->mac_addr,
- IPA_CMD_SETVMAC);
- } else {
- return qeth_l2_send_setgroupmac(card, mac->mac_addr);
- }
-}
-
-static int qeth_l2_remove_mac(struct qeth_card *card, struct qeth_mac *mac)
-{
- if (mac->is_uc) {
- return qeth_l2_send_setdelmac(card, mac->mac_addr,
- IPA_CMD_DELVMAC);
- } else {
- return qeth_l2_send_delgroupmac(card, mac->mac_addr);
- }
-}
-
static void qeth_l2_del_all_macs(struct qeth_card *card)
{
struct qeth_mac *mac;
@@ -549,7 +532,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
QETH_CARD_TEXT(card, 3, "setmcTYP");
return -EOPNOTSUPP;
}
- QETH_CARD_HEX(card, 3, addr->sa_data, OSA_ADDR_LEN);
+ QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
QETH_CARD_TEXT(card, 3, "setmcREC");
return -ERESTARTSYS;
@@ -597,27 +580,23 @@ static void qeth_promisc_to_bridge(struct qeth_card *card)
* only if there is not in the hash table storage already
*
*/
-static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha,
- u8 is_uc)
+static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha)
{
u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2]));
struct qeth_mac *mac;
hash_for_each_possible(card->mac_htable, mac, hnode, mac_hash) {
- if (is_uc == mac->is_uc &&
- !memcmp(ha->addr, mac->mac_addr, OSA_ADDR_LEN)) {
+ if (ether_addr_equal_64bits(ha->addr, mac->mac_addr)) {
mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
return;
}
}
mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC);
-
if (!mac)
return;
- memcpy(mac->mac_addr, ha->addr, OSA_ADDR_LEN);
- mac->is_uc = is_uc;
+ ether_addr_copy(mac->mac_addr, ha->addr);
mac->disp_flag = QETH_DISP_ADDR_ADD;
hash_add(card->mac_htable, &mac->hnode, mac_hash);
@@ -643,26 +622,29 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
spin_lock_bh(&card->mclock);
netdev_for_each_mc_addr(ha, dev)
- qeth_l2_add_mac(card, ha, 0);
-
+ qeth_l2_add_mac(card, ha);
netdev_for_each_uc_addr(ha, dev)
- qeth_l2_add_mac(card, ha, 1);
+ qeth_l2_add_mac(card, ha);
hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) {
- if (mac->disp_flag == QETH_DISP_ADDR_DELETE) {
- qeth_l2_remove_mac(card, mac);
+ switch (mac->disp_flag) {
+ case QETH_DISP_ADDR_DELETE:
+ qeth_l2_remove_mac(card, mac->mac_addr);
hash_del(&mac->hnode);
kfree(mac);
-
- } else if (mac->disp_flag == QETH_DISP_ADDR_ADD) {
- rc = qeth_l2_write_mac(card, mac);
+ break;
+ case QETH_DISP_ADDR_ADD:
+ rc = qeth_l2_write_mac(card, mac->mac_addr);
if (rc) {
hash_del(&mac->hnode);
kfree(mac);
- } else
- mac->disp_flag = QETH_DISP_ADDR_DELETE;
- } else
+ break;
+ }
+ /* fall through */
+ default:
+ /* for next call to set_rx_mode(): */
mac->disp_flag = QETH_DISP_ADDR_DELETE;
+ }
}
spin_unlock_bh(&card->mclock);
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index e5833837b799..bdd45f4dcace 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -29,7 +29,7 @@ struct qeth_ipaddr {
*/
int ref_counter;
enum qeth_prot_versions proto;
- unsigned char mac[OSA_ADDR_LEN];
+ unsigned char mac[ETH_ALEN];
union {
struct {
unsigned int addr;
@@ -69,19 +69,20 @@ struct qeth_ipato_entry {
extern const struct attribute_group *qeth_l3_attr_groups[];
void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *);
-int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *);
int qeth_l3_create_device_attributes(struct device *);
void qeth_l3_remove_device_attributes(struct device *);
int qeth_l3_setrouting_v4(struct qeth_card *);
int qeth_l3_setrouting_v6(struct qeth_card *);
int qeth_l3_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *);
-void qeth_l3_del_ipato_entry(struct qeth_card *, enum qeth_prot_versions,
- u8 *, int);
+int qeth_l3_del_ipato_entry(struct qeth_card *card,
+ enum qeth_prot_versions proto, u8 *addr,
+ int mask_bits);
int qeth_l3_add_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
-void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
+int qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
+ const u8 *addr);
int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
-void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions,
- const u8 *);
+int qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
+ const u8 *addr);
void qeth_l3_update_ipato(struct qeth_card *card);
struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions);
int qeth_l3_add_ip(struct qeth_card *, struct qeth_ipaddr *);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index ef0961e18686..b0c888e86cd4 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -18,15 +18,20 @@
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
+#include <linux/in.h>
#include <linux/ipv6.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
#include <linux/slab.h>
+#include <linux/if_ether.h>
#include <linux/if_vlan.h>
+#include <linux/skbuff.h>
#include <net/ip.h>
#include <net/arp.h>
#include <net/route.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
#include <net/ip6_fib.h>
#include <net/ip6_checksum.h>
#include <net/iucv/af_iucv.h>
@@ -37,99 +42,22 @@
static int qeth_l3_set_offline(struct ccwgroup_device *);
static int qeth_l3_stop(struct net_device *);
-static void qeth_l3_set_multicast_list(struct net_device *);
+static void qeth_l3_set_rx_mode(struct net_device *dev);
static int qeth_l3_register_addr_entry(struct qeth_card *,
struct qeth_ipaddr *);
static int qeth_l3_deregister_addr_entry(struct qeth_card *,
struct qeth_ipaddr *);
-static int qeth_l3_isxdigit(char *buf)
-{
- while (*buf) {
- if (!isxdigit(*buf++))
- return 0;
- }
- return 1;
-}
-
static void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf)
{
sprintf(buf, "%pI4", addr);
}
-static int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
-{
- int count = 0, rc = 0;
- unsigned int in[4];
- char c;
-
- rc = sscanf(buf, "%u.%u.%u.%u%c",
- &in[0], &in[1], &in[2], &in[3], &c);
- if (rc != 4 && (rc != 5 || c != '\n'))
- return -EINVAL;
- for (count = 0; count < 4; count++) {
- if (in[count] > 255)
- return -EINVAL;
- addr[count] = in[count];
- }
- return 0;
-}
-
static void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
{
sprintf(buf, "%pI6", addr);
}
-static int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr)
-{
- const char *end, *end_tmp, *start;
- __u16 *in;
- char num[5];
- int num2, cnt, out, found, save_cnt;
- unsigned short in_tmp[8] = {0, };
-
- cnt = out = found = save_cnt = num2 = 0;
- end = start = buf;
- in = (__u16 *) addr;
- memset(in, 0, 16);
- while (*end) {
- end = strchr(start, ':');
- if (end == NULL) {
- end = buf + strlen(buf);
- end_tmp = strchr(start, '\n');
- if (end_tmp != NULL)
- end = end_tmp;
- out = 1;
- }
- if ((end - start)) {
- memset(num, 0, 5);
- if ((end - start) > 4)
- return -EINVAL;
- memcpy(num, start, end - start);
- if (!qeth_l3_isxdigit(num))
- return -EINVAL;
- sscanf(start, "%x", &num2);
- if (found)
- in_tmp[save_cnt++] = num2;
- else
- in[cnt++] = num2;
- if (out)
- break;
- } else {
- if (found)
- return -EINVAL;
- found = 1;
- }
- start = ++end;
- }
- if (cnt + save_cnt > 8)
- return -EINVAL;
- cnt = 7;
- while (save_cnt)
- in[cnt--] = in_tmp[--save_cnt];
- return 0;
-}
-
void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
char *buf)
{
@@ -139,17 +67,6 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
qeth_l3_ipaddr6_to_string(addr, buf);
}
-int qeth_l3_string_to_ipaddr(const char *buf, enum qeth_prot_versions proto,
- __u8 *addr)
-{
- if (proto == QETH_PROT_IPV4)
- return qeth_l3_string_to_ipaddr4(buf, addr);
- else if (proto == QETH_PROT_IPV6)
- return qeth_l3_string_to_ipaddr6(buf, addr);
- else
- return -EINVAL;
-}
-
static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
{
int i, j;
@@ -207,8 +124,8 @@ inline int
qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2)
{
return addr1->proto == addr2->proto &&
- !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) &&
- !memcmp(&addr1->mac, &addr2->mac, sizeof(addr1->mac));
+ !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) &&
+ ether_addr_equal_64bits(addr1->mac, addr2->mac);
}
static struct qeth_ipaddr *
@@ -446,7 +363,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
if (!iob)
return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- memcpy(&cmd->data.setdelipm.mac, addr->mac, OSA_ADDR_LEN);
+ ether_addr_copy(cmd->data.setdelipm.mac, addr->mac);
if (addr->proto == QETH_PROT_IPV6)
memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr,
sizeof(struct in6_addr));
@@ -582,7 +499,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
int rc = 0;
QETH_CARD_TEXT(card, 3, "setrtg6");
-#ifdef CONFIG_QETH_IPV6
if (!qeth_is_supported(card, IPA_IPV6))
return 0;
@@ -599,7 +515,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
" on %s. Type set to 'no router'.\n", rc,
QETH_CARD_IFNAME(card));
}
-#endif
return rc;
}
@@ -673,10 +588,12 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card,
return rc;
}
-void qeth_l3_del_ipato_entry(struct qeth_card *card,
- enum qeth_prot_versions proto, u8 *addr, int mask_bits)
+int qeth_l3_del_ipato_entry(struct qeth_card *card,
+ enum qeth_prot_versions proto, u8 *addr,
+ int mask_bits)
{
struct qeth_ipato_entry *ipatoe, *tmp;
+ int rc = -ENOENT;
QETH_CARD_TEXT(card, 2, "delipato");
@@ -691,10 +608,12 @@ void qeth_l3_del_ipato_entry(struct qeth_card *card,
list_del(&ipatoe->entry);
qeth_l3_update_ipato(card);
kfree(ipatoe);
+ rc = 0;
}
}
spin_unlock_bh(&card->ip_lock);
+ return rc;
}
/*
@@ -704,7 +623,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
const u8 *addr)
{
struct qeth_ipaddr *ipaddr;
- int rc = 0;
+ int rc;
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
@@ -728,7 +647,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
if (qeth_l3_ip_from_hash(card, ipaddr))
rc = -EEXIST;
else
- qeth_l3_add_ip(card, ipaddr);
+ rc = qeth_l3_add_ip(card, ipaddr);
spin_unlock_bh(&card->ip_lock);
@@ -737,10 +656,11 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
return rc;
}
-void qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
- const u8 *addr)
+int qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
+ const u8 *addr)
{
struct qeth_ipaddr *ipaddr;
+ int rc;
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
@@ -755,13 +675,14 @@ void qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
}
ipaddr->type = QETH_IP_TYPE_VIPA;
} else
- return;
+ return -ENOMEM;
spin_lock_bh(&card->ip_lock);
- qeth_l3_delete_ip(card, ipaddr);
+ rc = qeth_l3_delete_ip(card, ipaddr);
spin_unlock_bh(&card->ip_lock);
kfree(ipaddr);
+ return rc;
}
/*
@@ -771,7 +692,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
const u8 *addr)
{
struct qeth_ipaddr *ipaddr;
- int rc = 0;
+ int rc;
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
@@ -796,7 +717,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
if (qeth_l3_ip_from_hash(card, ipaddr))
rc = -EEXIST;
else
- qeth_l3_add_ip(card, ipaddr);
+ rc = qeth_l3_add_ip(card, ipaddr);
spin_unlock_bh(&card->ip_lock);
@@ -805,10 +726,11 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
return rc;
}
-void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
- const u8 *addr)
+int qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
+ const u8 *addr)
{
struct qeth_ipaddr *ipaddr;
+ int rc;
ipaddr = qeth_l3_get_addr_buffer(proto);
if (ipaddr) {
@@ -823,13 +745,14 @@ void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
}
ipaddr->type = QETH_IP_TYPE_RXIP;
} else
- return;
+ return -ENOMEM;
spin_lock_bh(&card->ip_lock);
- qeth_l3_delete_ip(card, ipaddr);
+ rc = qeth_l3_delete_ip(card, ipaddr);
spin_unlock_bh(&card->ip_lock);
kfree(ipaddr);
+ return rc;
}
static int qeth_l3_register_addr_entry(struct qeth_card *card,
@@ -896,27 +819,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
return rc;
}
-static u8 qeth_l3_get_qeth_hdr_flags4(int cast_type)
-{
- if (cast_type == RTN_MULTICAST)
- return QETH_CAST_MULTICAST;
- if (cast_type == RTN_BROADCAST)
- return QETH_CAST_BROADCAST;
- return QETH_CAST_UNICAST;
-}
-
-static u8 qeth_l3_get_qeth_hdr_flags6(int cast_type)
-{
- u8 ct = QETH_HDR_PASSTHRU | QETH_HDR_IPV6;
- if (cast_type == RTN_MULTICAST)
- return ct | QETH_CAST_MULTICAST;
- if (cast_type == RTN_ANYCAST)
- return ct | QETH_CAST_ANYCAST;
- if (cast_type == RTN_BROADCAST)
- return ct | QETH_CAST_BROADCAST;
- return ct | QETH_CAST_UNICAST;
-}
-
static int qeth_l3_setadapter_parms(struct qeth_card *card)
{
int rc = 0;
@@ -933,7 +835,6 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card)
return rc;
}
-#ifdef CONFIG_QETH_IPV6
static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func, __u16 cmd_code)
{
@@ -949,7 +850,6 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
qeth_setassparms_cb, NULL);
return rc;
}
-#endif
static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
{
@@ -1045,7 +945,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
return rc;
}
-#ifdef CONFIG_QETH_IPV6
static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
{
int rc;
@@ -1091,12 +990,9 @@ out:
dev_info(&card->gdev->dev, "IPV6 enabled\n");
return 0;
}
-#endif
static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
{
- int rc = 0;
-
QETH_CARD_TEXT(card, 3, "strtipv6");
if (!qeth_is_supported(card, IPA_IPV6)) {
@@ -1104,10 +1000,7 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
"IPv6 not supported on %s\n", QETH_CARD_IFNAME(card));
return 0;
}
-#ifdef CONFIG_QETH_IPV6
- rc = qeth_l3_softsetup_ipv6(card);
-#endif
- return rc ;
+ return qeth_l3_softsetup_ipv6(card);
}
static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
@@ -1179,8 +1072,8 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code == 0)
- memcpy(card->dev->dev_addr,
- cmd->data.create_destroy_addr.unique_id, ETH_ALEN);
+ ether_addr_copy(card->dev->dev_addr,
+ cmd->data.create_destroy_addr.unique_id);
else
eth_random_addr(card->dev->dev_addr);
@@ -1328,81 +1221,22 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
}
-static void qeth_l3_get_mac_for_ipm(__be32 ipm, char *mac)
-{
- ip_eth_mc_map(ipm, mac);
-}
-
-static void qeth_l3_mark_all_mc_to_be_deleted(struct qeth_card *card)
-{
- struct qeth_ipaddr *addr;
- int i;
-
- hash_for_each(card->ip_mc_htable, i, addr, hnode)
- addr->disp_flag = QETH_DISP_ADDR_DELETE;
-
-}
-
-static void qeth_l3_add_all_new_mc(struct qeth_card *card)
-{
- struct qeth_ipaddr *addr;
- struct hlist_node *tmp;
- int i;
- int rc;
-
- hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
- if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
- rc = qeth_l3_register_addr_entry(card, addr);
- if (!rc || (rc == IPA_RC_LAN_OFFLINE))
- addr->ref_counter = 1;
- else {
- hash_del(&addr->hnode);
- kfree(addr);
- }
- }
- }
-
-}
-
-static void qeth_l3_delete_nonused_mc(struct qeth_card *card)
-{
- struct qeth_ipaddr *addr;
- struct hlist_node *tmp;
- int i;
- int rc;
-
- hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
- if (addr->disp_flag == QETH_DISP_ADDR_DELETE) {
- rc = qeth_l3_deregister_addr_entry(card, addr);
- if (!rc || (rc == IPA_RC_MC_ADDR_NOT_FOUND)) {
- hash_del(&addr->hnode);
- kfree(addr);
- }
- }
- }
-
-}
-
-
static void
qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
{
struct ip_mc_list *im4;
struct qeth_ipaddr *tmp, *ipm;
- char buf[MAX_ADDR_LEN];
QETH_CARD_TEXT(card, 4, "addmc");
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
- if (!tmp)
- return;
+ if (!tmp)
+ return;
for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL;
im4 = rcu_dereference(im4->next_rcu)) {
- qeth_l3_get_mac_for_ipm(im4->multiaddr, buf);
-
+ ip_eth_mc_map(im4->multiaddr, tmp->mac);
tmp->u.a4.addr = be32_to_cpu(im4->multiaddr);
- memcpy(tmp->mac, buf, sizeof(tmp->mac));
tmp->is_multicast = 1;
ipm = qeth_l3_ip_from_hash(card, tmp);
@@ -1412,7 +1246,7 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!ipm)
continue;
- memcpy(ipm->mac, buf, sizeof(tmp->mac));
+ ether_addr_copy(ipm->mac, tmp->mac);
ipm->u.a4.addr = be32_to_cpu(im4->multiaddr);
ipm->is_multicast = 1;
ipm->disp_flag = QETH_DISP_ADDR_ADD;
@@ -1466,25 +1300,21 @@ unlock:
rcu_read_unlock();
}
-#ifdef CONFIG_QETH_IPV6
-static void
-qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev)
+static void qeth_l3_add_mc6_to_hash(struct qeth_card *card,
+ struct inet6_dev *in6_dev)
{
struct qeth_ipaddr *ipm;
struct ifmcaddr6 *im6;
struct qeth_ipaddr *tmp;
- char buf[MAX_ADDR_LEN];
QETH_CARD_TEXT(card, 4, "addmc6");
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
- if (!tmp)
- return;
+ if (!tmp)
+ return;
for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
- ndisc_mc_map(&im6->mca_addr, buf, in6_dev->dev, 0);
-
- memcpy(tmp->mac, buf, sizeof(tmp->mac));
+ ipv6_eth_mc_map(&im6->mca_addr, tmp->mac);
memcpy(&tmp->u.a6.addr, &im6->mca_addr.s6_addr,
sizeof(struct in6_addr));
tmp->is_multicast = 1;
@@ -1499,7 +1329,7 @@ qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev)
if (!ipm)
continue;
- memcpy(ipm->mac, buf, OSA_ADDR_LEN);
+ ether_addr_copy(ipm->mac, tmp->mac);
memcpy(&ipm->u.a6.addr, &im6->mca_addr.s6_addr,
sizeof(struct in6_addr));
ipm->is_multicast = 1;
@@ -1560,7 +1390,6 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
rcu_read_unlock();
in6_dev_put(in6_dev);
}
-#endif /* CONFIG_QETH_IPV6 */
static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,
unsigned short vid)
@@ -1600,9 +1429,8 @@ out:
}
static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
- unsigned short vid)
+ unsigned short vid)
{
-#ifdef CONFIG_QETH_IPV6
struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifa;
struct qeth_ipaddr *addr;
@@ -1637,7 +1465,6 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
kfree(addr);
out:
in6_dev_put(in6_dev);
-#endif /* CONFIG_QETH_IPV6 */
}
static void qeth_l3_free_vlan_addresses(struct qeth_card *card,
@@ -1672,44 +1499,31 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
/* unregister IP addresses of vlan device */
qeth_l3_free_vlan_addresses(card, vid);
clear_bit(vid, card->active_vlans);
- qeth_l3_set_multicast_list(card->dev);
+ qeth_l3_set_rx_mode(dev);
return 0;
}
static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
- __u16 prot;
- struct iphdr *ip_hdr;
- unsigned char tg_addr[MAX_ADDR_LEN];
-
if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
- prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
- ETH_P_IP;
+ u16 prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
+ ETH_P_IP;
+ unsigned char tg_addr[ETH_ALEN];
+
+ skb_reset_network_header(skb);
switch (hdr->hdr.l3.flags & QETH_HDR_CAST_MASK) {
case QETH_CAST_MULTICAST:
- switch (prot) {
-#ifdef CONFIG_QETH_IPV6
- case ETH_P_IPV6:
- ndisc_mc_map((struct in6_addr *)
- skb->data + 24,
- tg_addr, card->dev, 0);
- break;
-#endif
- case ETH_P_IP:
- ip_hdr = (struct iphdr *)skb->data;
- ip_eth_mc_map(ip_hdr->daddr, tg_addr);
- break;
- default:
- memcpy(tg_addr, card->dev->broadcast,
- card->dev->addr_len);
- }
+ if (prot == ETH_P_IP)
+ ip_eth_mc_map(ip_hdr(skb)->daddr, tg_addr);
+ else
+ ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr);
+
card->stats.multicast++;
skb->pkt_type = PACKET_MULTICAST;
break;
case QETH_CAST_BROADCAST:
- memcpy(tg_addr, card->dev->broadcast,
- card->dev->addr_len);
+ ether_addr_copy(tg_addr, card->dev->broadcast);
card->stats.multicast++;
skb->pkt_type = PACKET_BROADCAST;
break;
@@ -1721,12 +1535,11 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
skb->pkt_type = PACKET_OTHERHOST;
else
skb->pkt_type = PACKET_HOST;
- memcpy(tg_addr, card->dev->dev_addr,
- card->dev->addr_len);
+ ether_addr_copy(tg_addr, card->dev->dev_addr);
}
if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
card->dev->header_ops->create(skb, card->dev, prot,
- tg_addr, &hdr->hdr.l3.dest_addr[2],
+ tg_addr, &hdr->hdr.l3.next_hop.rx.src_mac,
card->dev->addr_len);
else
card->dev->header_ops->create(skb, card->dev, prot,
@@ -1741,7 +1554,7 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
QETH_HDR_EXT_INCLUDE_VLAN_TAG))) {
u16 tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
hdr->hdr.l3.vlan_id :
- *((u16 *)&hdr->hdr.l3.dest_addr[12]);
+ hdr->hdr.l3.next_hop.rx.vlan_id;
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
}
@@ -1949,26 +1762,46 @@ qeth_l3_handle_promisc_mode(struct qeth_card *card)
}
}
-static void qeth_l3_set_multicast_list(struct net_device *dev)
+static void qeth_l3_set_rx_mode(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
+ struct qeth_ipaddr *addr;
+ struct hlist_node *tmp;
+ int i, rc;
QETH_CARD_TEXT(card, 3, "setmulti");
if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
(card->state != CARD_STATE_UP))
return;
if (!card->options.sniffer) {
-
spin_lock_bh(&card->mclock);
- qeth_l3_mark_all_mc_to_be_deleted(card);
-
qeth_l3_add_multicast_ipv4(card);
-#ifdef CONFIG_QETH_IPV6
qeth_l3_add_multicast_ipv6(card);
-#endif
- qeth_l3_delete_nonused_mc(card);
- qeth_l3_add_all_new_mc(card);
+
+ hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
+ switch (addr->disp_flag) {
+ case QETH_DISP_ADDR_DELETE:
+ rc = qeth_l3_deregister_addr_entry(card, addr);
+ if (!rc || rc == IPA_RC_MC_ADDR_NOT_FOUND) {
+ hash_del(&addr->hnode);
+ kfree(addr);
+ }
+ break;
+ case QETH_DISP_ADDR_ADD:
+ rc = qeth_l3_register_addr_entry(card, addr);
+ if (rc && rc != IPA_RC_LAN_OFFLINE) {
+ hash_del(&addr->hnode);
+ kfree(addr);
+ break;
+ }
+ addr->ref_counter = 1;
+ /* fall through */
+ default:
+ /* for next call to set_rx_mode(): */
+ addr->disp_flag = QETH_DISP_ADDR_DELETE;
+ }
+ }
spin_unlock_bh(&card->mclock);
@@ -2237,12 +2070,10 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
rc = -EFAULT;
goto free_and_out;
}
-#ifdef CONFIG_QETH_IPV6
if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) {
/* fails in case of GuestLAN QDIO mode */
qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, &qinfo);
}
-#endif
if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) {
QETH_CARD_TEXT(card, 4, "qactf");
rc = -EFAULT;
@@ -2422,9 +2253,8 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
-static int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
+static int qeth_l3_get_cast_type(struct sk_buff *skb)
{
- int cast_type = RTN_UNSPEC;
struct neighbour *n = NULL;
struct dst_entry *dst;
@@ -2433,48 +2263,34 @@ static int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
if (dst)
n = dst_neigh_lookup_skb(dst, skb);
if (n) {
- cast_type = n->type;
+ int cast_type = n->type;
+
rcu_read_unlock();
neigh_release(n);
if ((cast_type == RTN_BROADCAST) ||
(cast_type == RTN_MULTICAST) ||
(cast_type == RTN_ANYCAST))
return cast_type;
- else
- return RTN_UNSPEC;
+ return RTN_UNSPEC;
}
rcu_read_unlock();
- /* try something else */
+ /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
if (be16_to_cpu(skb->protocol) == ETH_P_IPV6)
- return (skb_network_header(skb)[24] == 0xff) ?
- RTN_MULTICAST : 0;
+ return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
+ RTN_MULTICAST : RTN_UNSPEC;
else if (be16_to_cpu(skb->protocol) == ETH_P_IP)
- return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ?
- RTN_MULTICAST : 0;
- /* ... */
- if (!memcmp(skb->data, skb->dev->broadcast, 6))
+ return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
+ RTN_MULTICAST : RTN_UNSPEC;
+
+ /* ... and MAC address */
+ if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, skb->dev->broadcast))
return RTN_BROADCAST;
- else {
- u16 hdr_mac;
-
- hdr_mac = *((u16 *)skb->data);
- /* tr multicast? */
- switch (card->info.link_type) {
- case QETH_LINK_TYPE_HSTR:
- case QETH_LINK_TYPE_LANE_TR:
- if ((hdr_mac == QETH_TR_MAC_NC) ||
- (hdr_mac == QETH_TR_MAC_C))
- return RTN_MULTICAST;
- break;
- /* eth or so multicast? */
- default:
- if ((hdr_mac == QETH_ETH_MAC_V4) ||
- (hdr_mac == QETH_ETH_MAC_V6))
- return RTN_MULTICAST;
- }
- }
- return cast_type;
+ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
+ return RTN_MULTICAST;
+
+ /* default to unicast */
+ return RTN_UNSPEC;
}
static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
@@ -2494,17 +2310,27 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
daddr[0] = 0xfe;
daddr[1] = 0x80;
memcpy(&daddr[8], iucv_hdr->destUserID, 8);
- memcpy(hdr->hdr.l3.dest_addr, daddr, 16);
+ memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16);
}
-static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
- struct sk_buff *skb, int ipv, int cast_type)
+static u8 qeth_l3_cast_type_to_flag(int cast_type)
{
- struct dst_entry *dst;
+ if (cast_type == RTN_MULTICAST)
+ return QETH_CAST_MULTICAST;
+ if (cast_type == RTN_ANYCAST)
+ return QETH_CAST_ANYCAST;
+ if (cast_type == RTN_BROADCAST)
+ return QETH_CAST_BROADCAST;
+ return QETH_CAST_UNICAST;
+}
+static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
+ struct sk_buff *skb, int ipv, int cast_type,
+ unsigned int data_len)
+{
memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
- hdr->hdr.l3.ext_flags = 0;
+ hdr->hdr.l3.length = data_len;
/*
* before we're going to overwrite this location with next hop ip.
@@ -2518,44 +2344,40 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
}
- hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr);
+ /* OSA only: */
+ if (!ipv) {
+ hdr->hdr.l3.flags = QETH_HDR_PASSTHRU;
+ if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
+ skb->dev->broadcast))
+ hdr->hdr.l3.flags |= QETH_CAST_BROADCAST;
+ else
+ hdr->hdr.l3.flags |= (cast_type == RTN_MULTICAST) ?
+ QETH_CAST_MULTICAST : QETH_CAST_UNICAST;
+ return;
+ }
+ hdr->hdr.l3.flags = qeth_l3_cast_type_to_flag(cast_type);
rcu_read_lock();
- dst = skb_dst(skb);
if (ipv == 4) {
- struct rtable *rt = (struct rtable *) dst;
- __be32 *pkey = &ip_hdr(skb)->daddr;
-
- if (rt && rt->rt_gateway)
- pkey = &rt->rt_gateway;
+ struct rtable *rt = skb_rtable(skb);
- /* IPv4 */
- hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type);
- memset(hdr->hdr.l3.dest_addr, 0, 12);
- *((__be32 *) (&hdr->hdr.l3.dest_addr[12])) = *pkey;
- } else if (ipv == 6) {
- struct rt6_info *rt = (struct rt6_info *) dst;
- struct in6_addr *pkey = &ipv6_hdr(skb)->daddr;
+ *((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ?
+ rt_nexthop(rt, ip_hdr(skb)->daddr) :
+ ip_hdr(skb)->daddr;
+ } else {
+ /* IPv6 */
+ const struct rt6_info *rt = skb_rt6_info(skb);
+ const struct in6_addr *next_hop;
if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
- pkey = &rt->rt6i_gateway;
+ next_hop = &rt->rt6i_gateway;
+ else
+ next_hop = &ipv6_hdr(skb)->daddr;
+ memcpy(hdr->hdr.l3.next_hop.ipv6_addr, next_hop, 16);
- /* IPv6 */
- hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type);
- if (card->info.type == QETH_CARD_TYPE_IQD)
- hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU;
- memcpy(hdr->hdr.l3.dest_addr, pkey, 16);
- } else {
- if (!memcmp(skb->data + sizeof(struct qeth_hdr),
- skb->dev->broadcast, 6)) {
- /* broadcast? */
- hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
- QETH_HDR_PASSTHRU;
- } else {
- hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ?
- QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
- QETH_CAST_UNICAST | QETH_HDR_PASSTHRU;
- }
+ hdr->hdr.l3.flags |= QETH_HDR_IPV6;
+ if (card->info.type != QETH_CARD_TYPE_IQD)
+ hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU;
}
rcu_read_unlock();
}
@@ -2587,7 +2409,6 @@ static void qeth_tso_fill_header(struct qeth_card *card,
/*fix header to TSO values ...*/
hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
- hdr->hdr.hdr.l3.length = skb->len - sizeof(struct qeth_hdr_tso);
/*set values which are fix for the first approach ...*/
hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
hdr->ext.imb_hdr_no = 1;
@@ -2655,7 +2476,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
struct qeth_card *card = dev->ml_priv;
struct sk_buff *new_skb = NULL;
int ipv = qeth_get_ip_version(skb);
- int cast_type = qeth_l3_get_cast_type(card, skb);
+ int cast_type = qeth_l3_get_cast_type(skb);
struct qeth_qdio_out_q *queue =
card->qdio.out_qs[card->qdio.do_prio_queueing
|| (cast_type && card->info.is_multicast_different) ?
@@ -2748,21 +2569,23 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
if (use_tso) {
hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso));
memset(hdr, 0, sizeof(struct qeth_hdr_tso));
- qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
+ qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
+ new_skb->len - sizeof(struct qeth_hdr_tso));
qeth_tso_fill_header(card, hdr, new_skb);
hdr_elements++;
} else {
if (data_offset < 0) {
hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
- qeth_l3_fill_header(card, hdr, new_skb, ipv,
- cast_type);
+ qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
+ new_skb->len -
+ sizeof(struct qeth_hdr));
} else {
if (be16_to_cpu(new_skb->protocol) == ETH_P_AF_IUCV)
qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb);
else {
qeth_l3_fill_header(card, hdr, new_skb, ipv,
- cast_type);
- hdr->hdr.l3.length = new_skb->len - data_offset;
+ cast_type,
+ new_skb->len - data_offset);
}
}
@@ -2930,7 +2753,7 @@ static const struct net_device_ops qeth_l3_netdev_ops = {
.ndo_get_stats = qeth_get_stats,
.ndo_start_xmit = qeth_l3_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = qeth_l3_set_multicast_list,
+ .ndo_set_rx_mode = qeth_l3_set_rx_mode,
.ndo_do_ioctl = qeth_do_ioctl,
.ndo_change_mtu = qeth_change_mtu,
.ndo_fix_features = qeth_fix_features,
@@ -2947,7 +2770,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
.ndo_start_xmit = qeth_l3_hard_start_xmit,
.ndo_features_check = qeth_features_check,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = qeth_l3_set_multicast_list,
+ .ndo_set_rx_mode = qeth_l3_set_rx_mode,
.ndo_do_ioctl = qeth_do_ioctl,
.ndo_change_mtu = qeth_change_mtu,
.ndo_fix_features = qeth_fix_features,
@@ -3145,7 +2968,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
__qeth_l3_open(card->dev);
else
dev_open(card->dev);
- qeth_l3_set_multicast_list(card->dev);
+ qeth_l3_set_rx_mode(card->dev);
qeth_recover_features(card->dev);
rtnl_unlock();
}
@@ -3371,10 +3194,6 @@ static struct notifier_block qeth_l3_ip_notifier = {
NULL,
};
-#ifdef CONFIG_QETH_IPV6
-/**
- * IPv6 event handler
- */
static int qeth_l3_ip6_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
@@ -3419,7 +3238,6 @@ static struct notifier_block qeth_l3_ip6_notifier = {
qeth_l3_ip6_event,
NULL,
};
-#endif
static int qeth_l3_register_notifiers(void)
{
@@ -3429,35 +3247,25 @@ static int qeth_l3_register_notifiers(void)
rc = register_inetaddr_notifier(&qeth_l3_ip_notifier);
if (rc)
return rc;
-#ifdef CONFIG_QETH_IPV6
rc = register_inet6addr_notifier(&qeth_l3_ip6_notifier);
if (rc) {
unregister_inetaddr_notifier(&qeth_l3_ip_notifier);
return rc;
}
-#else
- pr_warn("There is no IPv6 support for the layer 3 discipline\n");
-#endif
return 0;
}
static void qeth_l3_unregister_notifiers(void)
{
-
QETH_DBF_TEXT(SETUP, 5, "unregnot");
WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));
-#ifdef CONFIG_QETH_IPV6
WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));
-#endif /* QETH_IPV6 */
}
static int __init qeth_l3_init(void)
{
- int rc = 0;
-
pr_info("register layer 3 discipline\n");
- rc = qeth_l3_register_notifiers();
- return rc;
+ return qeth_l3_register_notifiers();
}
static void __exit qeth_l3_exit(void)
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index 6ea2b528a64e..a645cfe66ddf 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -10,11 +10,23 @@
#include <linux/slab.h>
#include <asm/ebcdic.h>
#include <linux/hashtable.h>
+#include <linux/inet.h>
#include "qeth_l3.h"
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
+static int qeth_l3_string_to_ipaddr(const char *buf,
+ enum qeth_prot_versions proto, u8 *addr)
+{
+ const char *end;
+
+ if ((proto == QETH_PROT_IPV4 && !in4_pton(buf, -1, addr, -1, &end)) ||
+ (proto == QETH_PROT_IPV6 && !in6_pton(buf, -1, addr, -1, &end)))
+ return -EINVAL;
+ return 0;
+}
+
static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
struct qeth_routing_info *route, char *buf)
{
@@ -262,7 +274,7 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
struct qeth_ipaddr *addr;
char *tmp;
- int i;
+ int rc, i;
if (!card)
return -EINVAL;
@@ -331,11 +343,11 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
return -ENOMEM;
spin_lock_bh(&card->ip_lock);
- qeth_l3_add_ip(card, addr);
+ rc = qeth_l3_add_ip(card, addr);
spin_unlock_bh(&card->ip_lock);
kfree(addr);
- return count;
+ return rc ? rc : count;
}
static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show,
@@ -573,7 +585,7 @@ static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
if (!rc)
- qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
+ rc = qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
}
@@ -693,22 +705,25 @@ static const struct attribute_group qeth_device_ipato_group = {
.attrs = qeth_ipato_device_attrs,
};
-static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
- enum qeth_prot_versions proto)
+static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf,
+ enum qeth_prot_versions proto,
+ enum qeth_ip_types type)
{
+ struct qeth_card *card = dev_get_drvdata(dev);
struct qeth_ipaddr *ipaddr;
char addr_str[40];
int str_len = 0;
int entry_len; /* length of 1 entry string, differs between v4 and v6 */
int i;
+ if (!card)
+ return -EINVAL;
+
entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
entry_len += 2; /* \n + terminator */
spin_lock_bh(&card->ip_lock);
hash_for_each(card->ip_htable, i, ipaddr, hnode) {
- if (ipaddr->proto != proto)
- continue;
- if (ipaddr->type != QETH_IP_TYPE_VIPA)
+ if (ipaddr->proto != proto || ipaddr->type != type)
continue;
/* String must not be longer than PAGE_SIZE. So we check if
* string length gets near PAGE_SIZE. Then we can savely display
@@ -727,14 +742,11 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card,
}
static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
- struct qeth_card *card = dev_get_drvdata(dev);
-
- if (!card)
- return -EINVAL;
-
- return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
+ return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4,
+ QETH_IP_TYPE_VIPA);
}
static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto,
@@ -784,7 +796,7 @@ static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count,
mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_vipae(buf, proto, addr);
if (!rc)
- qeth_l3_del_vipa(card, proto, addr);
+ rc = qeth_l3_del_vipa(card, proto, addr);
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
}
@@ -804,14 +816,11 @@ static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
qeth_l3_dev_vipa_del4_store);
static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
- struct qeth_card *card = dev_get_drvdata(dev);
-
- if (!card)
- return -EINVAL;
-
- return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV6);
+ return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6,
+ QETH_IP_TYPE_VIPA);
}
static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev,
@@ -856,48 +865,12 @@ static const struct attribute_group qeth_device_vipa_group = {
.attrs = qeth_vipa_device_attrs,
};
-static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card,
- enum qeth_prot_versions proto)
-{
- struct qeth_ipaddr *ipaddr;
- char addr_str[40];
- int str_len = 0;
- int entry_len; /* length of 1 entry string, differs between v4 and v6 */
- int i;
-
- entry_len = (proto == QETH_PROT_IPV4)? 12 : 40;
- entry_len += 2; /* \n + terminator */
- spin_lock_bh(&card->ip_lock);
- hash_for_each(card->ip_htable, i, ipaddr, hnode) {
- if (ipaddr->proto != proto)
- continue;
- if (ipaddr->type != QETH_IP_TYPE_RXIP)
- continue;
- /* String must not be longer than PAGE_SIZE. So we check if
- * string length gets near PAGE_SIZE. Then we can savely display
- * the next IPv6 address (worst case, compared to IPv4) */
- if ((PAGE_SIZE - str_len) <= entry_len)
- break;
- qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u,
- addr_str);
- str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "%s\n",
- addr_str);
- }
- spin_unlock_bh(&card->ip_lock);
- str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "\n");
-
- return str_len;
-}
-
static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
- struct qeth_card *card = dev_get_drvdata(dev);
-
- if (!card)
- return -EINVAL;
-
- return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
+ return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4,
+ QETH_IP_TYPE_RXIP);
}
static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto,
@@ -964,7 +937,7 @@ static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count,
mutex_lock(&card->conf_mutex);
rc = qeth_l3_parse_rxipe(buf, proto, addr);
if (!rc)
- qeth_l3_del_rxip(card, proto, addr);
+ rc = qeth_l3_del_rxip(card, proto, addr);
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
}
@@ -984,14 +957,11 @@ static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
qeth_l3_dev_rxip_del4_store);
static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
- struct qeth_card *card = dev_get_drvdata(dev);
-
- if (!card)
- return -EINVAL;
-
- return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV6);
+ return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6,
+ QETH_IP_TYPE_RXIP);
}
static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev,
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index ba2e0856d22c..8f5c1d7f751a 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -1297,6 +1297,9 @@ static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event)
vcdev->device_lost = true;
rc = NOTIFY_DONE;
break;
+ case CIO_OPER:
+ rc = NOTIFY_OK;
+ break;
default:
rc = NOTIFY_DONE;
break;
@@ -1309,6 +1312,27 @@ static struct ccw_device_id virtio_ids[] = {
{},
};
+#ifdef CONFIG_PM_SLEEP
+static int virtio_ccw_freeze(struct ccw_device *cdev)
+{
+ struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+
+ return virtio_device_freeze(&vcdev->vdev);
+}
+
+static int virtio_ccw_restore(struct ccw_device *cdev)
+{
+ struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+ int ret;
+
+ ret = virtio_ccw_set_transport_rev(vcdev);
+ if (ret)
+ return ret;
+
+ return virtio_device_restore(&vcdev->vdev);
+}
+#endif
+
static struct ccw_driver virtio_ccw_driver = {
.driver = {
.owner = THIS_MODULE,
@@ -1321,6 +1345,11 @@ static struct ccw_driver virtio_ccw_driver = {
.set_online = virtio_ccw_online,
.notify = virtio_ccw_cio_notify,
.int_class = IRQIO_VIR,
+#ifdef CONFIG_PM_SLEEP
+ .freeze = virtio_ccw_freeze,
+ .thaw = virtio_ccw_restore,
+ .restore = virtio_ccw_restore,
+#endif
};
static int __init pure_hex(char **cp, unsigned int *val, int min_digit,