diff options
Diffstat (limited to 'drivers/s390/net')
29 files changed, 1452 insertions, 604 deletions
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index cb909a5b5047..977bb4d4ed15 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig | |||
@@ -43,6 +43,16 @@ config SMSGIUCV | |||
43 | Select this option if you want to be able to receive SMSG messages | 43 | Select this option if you want to be able to receive SMSG messages |
44 | from other VM guest systems. | 44 | from other VM guest systems. |
45 | 45 | ||
46 | config SMSGIUCV_EVENT | ||
47 | tristate "Deliver IUCV special messages as uevents (VM only)" | ||
48 | depends on SMSGIUCV | ||
49 | help | ||
50 | Select this option to deliver CP special messages (SMSGs) as | ||
51 | uevents. The driver handles only those special messages that | ||
52 | start with "APP". | ||
53 | |||
54 | To compile as a module, choose M. The module name is "smsgiucv_app". | ||
55 | |||
46 | config CLAW | 56 | config CLAW |
47 | tristate "CLAW device support" | 57 | tristate "CLAW device support" |
48 | depends on CCW && NETDEVICES | 58 | depends on CCW && NETDEVICES |
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 96eddb3b1d08..4dfe8c1092da 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile | |||
@@ -3,11 +3,12 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | ctcm-y += ctcm_main.o ctcm_fsms.o ctcm_mpc.o ctcm_sysfs.o ctcm_dbug.o | 5 | ctcm-y += ctcm_main.o ctcm_fsms.o ctcm_mpc.o ctcm_sysfs.o ctcm_dbug.o |
6 | obj-$(CONFIG_CTCM) += ctcm.o fsm.o cu3088.o | 6 | obj-$(CONFIG_CTCM) += ctcm.o fsm.o |
7 | obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o | 7 | obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o |
8 | obj-$(CONFIG_SMSGIUCV) += smsgiucv.o | 8 | obj-$(CONFIG_SMSGIUCV) += smsgiucv.o |
9 | obj-$(CONFIG_LCS) += lcs.o cu3088.o | 9 | obj-$(CONFIG_SMSGIUCV_EVENT) += smsgiucv_app.o |
10 | obj-$(CONFIG_CLAW) += claw.o cu3088.o | 10 | obj-$(CONFIG_LCS) += lcs.o |
11 | obj-$(CONFIG_CLAW) += claw.o | ||
11 | qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o | 12 | qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o |
12 | obj-$(CONFIG_QETH) += qeth.o | 13 | obj-$(CONFIG_QETH) += qeth.o |
13 | qeth_l2-y += qeth_l2_main.o | 14 | qeth_l2-y += qeth_l2_main.o |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index c63babefb698..147bb1a69aba 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -90,7 +90,6 @@ | |||
90 | #include <linux/timer.h> | 90 | #include <linux/timer.h> |
91 | #include <linux/types.h> | 91 | #include <linux/types.h> |
92 | 92 | ||
93 | #include "cu3088.h" | ||
94 | #include "claw.h" | 93 | #include "claw.h" |
95 | 94 | ||
96 | /* | 95 | /* |
@@ -258,6 +257,9 @@ static int claw_pm_prepare(struct ccwgroup_device *gdev) | |||
258 | return -EPERM; | 257 | return -EPERM; |
259 | } | 258 | } |
260 | 259 | ||
260 | /* the root device for claw group devices */ | ||
261 | static struct device *claw_root_dev; | ||
262 | |||
261 | /* ccwgroup table */ | 263 | /* ccwgroup table */ |
262 | 264 | ||
263 | static struct ccwgroup_driver claw_group_driver = { | 265 | static struct ccwgroup_driver claw_group_driver = { |
@@ -272,6 +274,47 @@ static struct ccwgroup_driver claw_group_driver = { | |||
272 | .prepare = claw_pm_prepare, | 274 | .prepare = claw_pm_prepare, |
273 | }; | 275 | }; |
274 | 276 | ||
277 | static struct ccw_device_id claw_ids[] = { | ||
278 | {CCW_DEVICE(0x3088, 0x61), .driver_info = claw_channel_type_claw}, | ||
279 | {}, | ||
280 | }; | ||
281 | MODULE_DEVICE_TABLE(ccw, claw_ids); | ||
282 | |||
283 | static struct ccw_driver claw_ccw_driver = { | ||
284 | .owner = THIS_MODULE, | ||
285 | .name = "claw", | ||
286 | .ids = claw_ids, | ||
287 | .probe = ccwgroup_probe_ccwdev, | ||
288 | .remove = ccwgroup_remove_ccwdev, | ||
289 | }; | ||
290 | |||
291 | static ssize_t | ||
292 | claw_driver_group_store(struct device_driver *ddrv, const char *buf, | ||
293 | size_t count) | ||
294 | { | ||
295 | int err; | ||
296 | err = ccwgroup_create_from_string(claw_root_dev, | ||
297 | claw_group_driver.driver_id, | ||
298 | &claw_ccw_driver, 3, buf); | ||
299 | return err ? err : count; | ||
300 | } | ||
301 | |||
302 | static DRIVER_ATTR(group, 0200, NULL, claw_driver_group_store); | ||
303 | |||
304 | static struct attribute *claw_group_attrs[] = { | ||
305 | &driver_attr_group.attr, | ||
306 | NULL, | ||
307 | }; | ||
308 | |||
309 | static struct attribute_group claw_group_attr_group = { | ||
310 | .attrs = claw_group_attrs, | ||
311 | }; | ||
312 | |||
313 | static const struct attribute_group *claw_group_attr_groups[] = { | ||
314 | &claw_group_attr_group, | ||
315 | NULL, | ||
316 | }; | ||
317 | |||
275 | /* | 318 | /* |
276 | * Key functions | 319 | * Key functions |
277 | */ | 320 | */ |
@@ -3326,7 +3369,11 @@ claw_remove_files(struct device *dev) | |||
3326 | static void __exit | 3369 | static void __exit |
3327 | claw_cleanup(void) | 3370 | claw_cleanup(void) |
3328 | { | 3371 | { |
3329 | unregister_cu3088_discipline(&claw_group_driver); | 3372 | driver_remove_file(&claw_group_driver.driver, |
3373 | &driver_attr_group); | ||
3374 | ccwgroup_driver_unregister(&claw_group_driver); | ||
3375 | ccw_driver_unregister(&claw_ccw_driver); | ||
3376 | root_device_unregister(claw_root_dev); | ||
3330 | claw_unregister_debug_facility(); | 3377 | claw_unregister_debug_facility(); |
3331 | pr_info("Driver unloaded\n"); | 3378 | pr_info("Driver unloaded\n"); |
3332 | 3379 | ||
@@ -3348,16 +3395,31 @@ claw_init(void) | |||
3348 | if (ret) { | 3395 | if (ret) { |
3349 | pr_err("Registering with the S/390 debug feature" | 3396 | pr_err("Registering with the S/390 debug feature" |
3350 | " failed with error code %d\n", ret); | 3397 | " failed with error code %d\n", ret); |
3351 | return ret; | 3398 | goto out_err; |
3352 | } | 3399 | } |
3353 | CLAW_DBF_TEXT(2, setup, "init_mod"); | 3400 | CLAW_DBF_TEXT(2, setup, "init_mod"); |
3354 | ret = register_cu3088_discipline(&claw_group_driver); | 3401 | claw_root_dev = root_device_register("claw"); |
3355 | if (ret) { | 3402 | ret = IS_ERR(claw_root_dev) ? PTR_ERR(claw_root_dev) : 0; |
3356 | CLAW_DBF_TEXT(2, setup, "init_bad"); | 3403 | if (ret) |
3357 | claw_unregister_debug_facility(); | 3404 | goto register_err; |
3358 | pr_err("Registering with the cu3088 device driver failed " | 3405 | ret = ccw_driver_register(&claw_ccw_driver); |
3359 | "with error code %d\n", ret); | 3406 | if (ret) |
3360 | } | 3407 | goto ccw_err; |
3408 | claw_group_driver.driver.groups = claw_group_attr_groups; | ||
3409 | ret = ccwgroup_driver_register(&claw_group_driver); | ||
3410 | if (ret) | ||
3411 | goto ccwgroup_err; | ||
3412 | return 0; | ||
3413 | |||
3414 | ccwgroup_err: | ||
3415 | ccw_driver_unregister(&claw_ccw_driver); | ||
3416 | ccw_err: | ||
3417 | root_device_unregister(claw_root_dev); | ||
3418 | register_err: | ||
3419 | CLAW_DBF_TEXT(2, setup, "init_bad"); | ||
3420 | claw_unregister_debug_facility(); | ||
3421 | out_err: | ||
3422 | pr_err("Initializing the claw device driver failed\n"); | ||
3361 | return ret; | 3423 | return ret; |
3362 | } | 3424 | } |
3363 | 3425 | ||
diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h index 005072c420d3..46d59a13db12 100644 --- a/drivers/s390/net/claw.h +++ b/drivers/s390/net/claw.h | |||
@@ -129,6 +129,18 @@ static inline int claw_dbf_passes(debug_info_t *dbf_grp, int level) | |||
129 | } \ | 129 | } \ |
130 | } while (0) | 130 | } while (0) |
131 | 131 | ||
132 | /** | ||
133 | * Enum for classifying detected devices. | ||
134 | */ | ||
135 | enum claw_channel_types { | ||
136 | /* Device is not a channel */ | ||
137 | claw_channel_type_none, | ||
138 | |||
139 | /* Device is a CLAW channel device */ | ||
140 | claw_channel_type_claw | ||
141 | }; | ||
142 | |||
143 | |||
132 | /******************************************************* | 144 | /******************************************************* |
133 | * Define Control Blocks * | 145 | * Define Control Blocks * |
134 | * * | 146 | * * |
diff --git a/drivers/s390/net/ctcm_dbug.c b/drivers/s390/net/ctcm_dbug.c index 1ca58f153470..d962fd741a23 100644 --- a/drivers/s390/net/ctcm_dbug.c +++ b/drivers/s390/net/ctcm_dbug.c | |||
@@ -10,7 +10,6 @@ | |||
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/slab.h> | ||
14 | #include <linux/ctype.h> | 13 | #include <linux/ctype.h> |
15 | #include <linux/sysctl.h> | 14 | #include <linux/sysctl.h> |
16 | #include <linux/module.h> | 15 | #include <linux/module.h> |
diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index 4ded9ac2c5ef..70eb7f138414 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c | |||
@@ -44,7 +44,6 @@ | |||
44 | #include <asm/idals.h> | 44 | #include <asm/idals.h> |
45 | 45 | ||
46 | #include "fsm.h" | 46 | #include "fsm.h" |
47 | #include "cu3088.h" | ||
48 | 47 | ||
49 | #include "ctcm_dbug.h" | 48 | #include "ctcm_dbug.h" |
50 | #include "ctcm_main.h" | 49 | #include "ctcm_main.h" |
diff --git a/drivers/s390/net/ctcm_fsms.h b/drivers/s390/net/ctcm_fsms.h index 2326aba9807a..046d077fabbb 100644 --- a/drivers/s390/net/ctcm_fsms.h +++ b/drivers/s390/net/ctcm_fsms.h | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <asm/idals.h> | 39 | #include <asm/idals.h> |
40 | 40 | ||
41 | #include "fsm.h" | 41 | #include "fsm.h" |
42 | #include "cu3088.h" | ||
43 | #include "ctcm_main.h" | 42 | #include "ctcm_main.h" |
44 | 43 | ||
45 | /* | 44 | /* |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index c5b83874500c..e35713dd0504 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -51,12 +51,16 @@ | |||
51 | 51 | ||
52 | #include <asm/idals.h> | 52 | #include <asm/idals.h> |
53 | 53 | ||
54 | #include "cu3088.h" | ||
55 | #include "ctcm_fsms.h" | 54 | #include "ctcm_fsms.h" |
56 | #include "ctcm_main.h" | 55 | #include "ctcm_main.h" |
57 | 56 | ||
58 | /* Some common global variables */ | 57 | /* Some common global variables */ |
59 | 58 | ||
59 | /** | ||
60 | * The root device for ctcm group devices | ||
61 | */ | ||
62 | static struct device *ctcm_root_dev; | ||
63 | |||
60 | /* | 64 | /* |
61 | * Linked list of all detected channels. | 65 | * Linked list of all detected channels. |
62 | */ | 66 | */ |
@@ -246,7 +250,7 @@ static void channel_remove(struct channel *ch) | |||
246 | * | 250 | * |
247 | * returns Pointer to a channel or NULL if no matching channel available. | 251 | * returns Pointer to a channel or NULL if no matching channel available. |
248 | */ | 252 | */ |
249 | static struct channel *channel_get(enum channel_types type, | 253 | static struct channel *channel_get(enum ctcm_channel_types type, |
250 | char *id, int direction) | 254 | char *id, int direction) |
251 | { | 255 | { |
252 | struct channel *ch = channels; | 256 | struct channel *ch = channels; |
@@ -1342,7 +1346,7 @@ static int ctcm_probe_device(struct ccwgroup_device *cgdev) | |||
1342 | * | 1346 | * |
1343 | * returns 0 on success, !0 on error. | 1347 | * returns 0 on success, !0 on error. |
1344 | */ | 1348 | */ |
1345 | static int add_channel(struct ccw_device *cdev, enum channel_types type, | 1349 | static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type, |
1346 | struct ctcm_priv *priv) | 1350 | struct ctcm_priv *priv) |
1347 | { | 1351 | { |
1348 | struct channel **c = &channels; | 1352 | struct channel **c = &channels; |
@@ -1501,13 +1505,13 @@ free_return: /* note that all channel pointers are 0 or valid */ | |||
1501 | /* | 1505 | /* |
1502 | * Return type of a detected device. | 1506 | * Return type of a detected device. |
1503 | */ | 1507 | */ |
1504 | static enum channel_types get_channel_type(struct ccw_device_id *id) | 1508 | static enum ctcm_channel_types get_channel_type(struct ccw_device_id *id) |
1505 | { | 1509 | { |
1506 | enum channel_types type; | 1510 | enum ctcm_channel_types type; |
1507 | type = (enum channel_types)id->driver_info; | 1511 | type = (enum ctcm_channel_types)id->driver_info; |
1508 | 1512 | ||
1509 | if (type == channel_type_ficon) | 1513 | if (type == ctcm_channel_type_ficon) |
1510 | type = channel_type_escon; | 1514 | type = ctcm_channel_type_escon; |
1511 | 1515 | ||
1512 | return type; | 1516 | return type; |
1513 | } | 1517 | } |
@@ -1525,16 +1529,21 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) | |||
1525 | char read_id[CTCM_ID_SIZE]; | 1529 | char read_id[CTCM_ID_SIZE]; |
1526 | char write_id[CTCM_ID_SIZE]; | 1530 | char write_id[CTCM_ID_SIZE]; |
1527 | int direction; | 1531 | int direction; |
1528 | enum channel_types type; | 1532 | enum ctcm_channel_types type; |
1529 | struct ctcm_priv *priv; | 1533 | struct ctcm_priv *priv; |
1530 | struct net_device *dev; | 1534 | struct net_device *dev; |
1531 | struct ccw_device *cdev0; | 1535 | struct ccw_device *cdev0; |
1532 | struct ccw_device *cdev1; | 1536 | struct ccw_device *cdev1; |
1537 | struct channel *readc; | ||
1538 | struct channel *writec; | ||
1533 | int ret; | 1539 | int ret; |
1540 | int result; | ||
1534 | 1541 | ||
1535 | priv = dev_get_drvdata(&cgdev->dev); | 1542 | priv = dev_get_drvdata(&cgdev->dev); |
1536 | if (!priv) | 1543 | if (!priv) { |
1537 | return -ENODEV; | 1544 | result = -ENODEV; |
1545 | goto out_err_result; | ||
1546 | } | ||
1538 | 1547 | ||
1539 | cdev0 = cgdev->cdev[0]; | 1548 | cdev0 = cgdev->cdev[0]; |
1540 | cdev1 = cgdev->cdev[1]; | 1549 | cdev1 = cgdev->cdev[1]; |
@@ -1545,31 +1554,40 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) | |||
1545 | snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); | 1554 | snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); |
1546 | 1555 | ||
1547 | ret = add_channel(cdev0, type, priv); | 1556 | ret = add_channel(cdev0, type, priv); |
1548 | if (ret) | 1557 | if (ret) { |
1549 | return ret; | 1558 | result = ret; |
1559 | goto out_err_result; | ||
1560 | } | ||
1550 | ret = add_channel(cdev1, type, priv); | 1561 | ret = add_channel(cdev1, type, priv); |
1551 | if (ret) | 1562 | if (ret) { |
1552 | return ret; | 1563 | result = ret; |
1564 | goto out_remove_channel1; | ||
1565 | } | ||
1553 | 1566 | ||
1554 | ret = ccw_device_set_online(cdev0); | 1567 | ret = ccw_device_set_online(cdev0); |
1555 | if (ret != 0) { | 1568 | if (ret != 0) { |
1556 | /* may be ok to fail now - can be done later */ | ||
1557 | CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, | 1569 | CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, |
1558 | "%s(%s) set_online rc=%d", | 1570 | "%s(%s) set_online rc=%d", |
1559 | CTCM_FUNTAIL, read_id, ret); | 1571 | CTCM_FUNTAIL, read_id, ret); |
1572 | result = -EIO; | ||
1573 | goto out_remove_channel2; | ||
1560 | } | 1574 | } |
1561 | 1575 | ||
1562 | ret = ccw_device_set_online(cdev1); | 1576 | ret = ccw_device_set_online(cdev1); |
1563 | if (ret != 0) { | 1577 | if (ret != 0) { |
1564 | /* may be ok to fail now - can be done later */ | ||
1565 | CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, | 1578 | CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, |
1566 | "%s(%s) set_online rc=%d", | 1579 | "%s(%s) set_online rc=%d", |
1567 | CTCM_FUNTAIL, write_id, ret); | 1580 | CTCM_FUNTAIL, write_id, ret); |
1581 | |||
1582 | result = -EIO; | ||
1583 | goto out_ccw1; | ||
1568 | } | 1584 | } |
1569 | 1585 | ||
1570 | dev = ctcm_init_netdevice(priv); | 1586 | dev = ctcm_init_netdevice(priv); |
1571 | if (dev == NULL) | 1587 | if (dev == NULL) { |
1572 | goto out; | 1588 | result = -ENODEV; |
1589 | goto out_ccw2; | ||
1590 | } | ||
1573 | 1591 | ||
1574 | for (direction = READ; direction <= WRITE; direction++) { | 1592 | for (direction = READ; direction <= WRITE; direction++) { |
1575 | priv->channel[direction] = | 1593 | priv->channel[direction] = |
@@ -1587,12 +1605,14 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) | |||
1587 | /* sysfs magic */ | 1605 | /* sysfs magic */ |
1588 | SET_NETDEV_DEV(dev, &cgdev->dev); | 1606 | SET_NETDEV_DEV(dev, &cgdev->dev); |
1589 | 1607 | ||
1590 | if (register_netdev(dev)) | 1608 | if (register_netdev(dev)) { |
1591 | goto out_dev; | 1609 | result = -ENODEV; |
1610 | goto out_dev; | ||
1611 | } | ||
1592 | 1612 | ||
1593 | if (ctcm_add_attributes(&cgdev->dev)) { | 1613 | if (ctcm_add_attributes(&cgdev->dev)) { |
1594 | unregister_netdev(dev); | 1614 | result = -ENODEV; |
1595 | goto out_dev; | 1615 | goto out_unregister; |
1596 | } | 1616 | } |
1597 | 1617 | ||
1598 | strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); | 1618 | strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); |
@@ -1608,13 +1628,22 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) | |||
1608 | priv->channel[WRITE]->id, priv->protocol); | 1628 | priv->channel[WRITE]->id, priv->protocol); |
1609 | 1629 | ||
1610 | return 0; | 1630 | return 0; |
1631 | out_unregister: | ||
1632 | unregister_netdev(dev); | ||
1611 | out_dev: | 1633 | out_dev: |
1612 | ctcm_free_netdevice(dev); | 1634 | ctcm_free_netdevice(dev); |
1613 | out: | 1635 | out_ccw2: |
1614 | ccw_device_set_offline(cgdev->cdev[1]); | 1636 | ccw_device_set_offline(cgdev->cdev[1]); |
1637 | out_ccw1: | ||
1615 | ccw_device_set_offline(cgdev->cdev[0]); | 1638 | ccw_device_set_offline(cgdev->cdev[0]); |
1616 | 1639 | out_remove_channel2: | |
1617 | return -ENODEV; | 1640 | readc = channel_get(type, read_id, READ); |
1641 | channel_remove(readc); | ||
1642 | out_remove_channel1: | ||
1643 | writec = channel_get(type, write_id, WRITE); | ||
1644 | channel_remove(writec); | ||
1645 | out_err_result: | ||
1646 | return result; | ||
1618 | } | 1647 | } |
1619 | 1648 | ||
1620 | /** | 1649 | /** |
@@ -1695,6 +1724,11 @@ static int ctcm_pm_suspend(struct ccwgroup_device *gdev) | |||
1695 | return 0; | 1724 | return 0; |
1696 | netif_device_detach(priv->channel[READ]->netdev); | 1725 | netif_device_detach(priv->channel[READ]->netdev); |
1697 | ctcm_close(priv->channel[READ]->netdev); | 1726 | ctcm_close(priv->channel[READ]->netdev); |
1727 | if (!wait_event_timeout(priv->fsm->wait_q, | ||
1728 | fsm_getstate(priv->fsm) == DEV_STATE_STOPPED, CTCM_TIME_5_SEC)) { | ||
1729 | netif_device_attach(priv->channel[READ]->netdev); | ||
1730 | return -EBUSY; | ||
1731 | } | ||
1698 | ccw_device_set_offline(gdev->cdev[1]); | 1732 | ccw_device_set_offline(gdev->cdev[1]); |
1699 | ccw_device_set_offline(gdev->cdev[0]); | 1733 | ccw_device_set_offline(gdev->cdev[0]); |
1700 | return 0; | 1734 | return 0; |
@@ -1719,6 +1753,22 @@ err_out: | |||
1719 | return rc; | 1753 | return rc; |
1720 | } | 1754 | } |
1721 | 1755 | ||
1756 | static struct ccw_device_id ctcm_ids[] = { | ||
1757 | {CCW_DEVICE(0x3088, 0x08), .driver_info = ctcm_channel_type_parallel}, | ||
1758 | {CCW_DEVICE(0x3088, 0x1e), .driver_info = ctcm_channel_type_ficon}, | ||
1759 | {CCW_DEVICE(0x3088, 0x1f), .driver_info = ctcm_channel_type_escon}, | ||
1760 | {}, | ||
1761 | }; | ||
1762 | MODULE_DEVICE_TABLE(ccw, ctcm_ids); | ||
1763 | |||
1764 | static struct ccw_driver ctcm_ccw_driver = { | ||
1765 | .owner = THIS_MODULE, | ||
1766 | .name = "ctcm", | ||
1767 | .ids = ctcm_ids, | ||
1768 | .probe = ccwgroup_probe_ccwdev, | ||
1769 | .remove = ccwgroup_remove_ccwdev, | ||
1770 | }; | ||
1771 | |||
1722 | static struct ccwgroup_driver ctcm_group_driver = { | 1772 | static struct ccwgroup_driver ctcm_group_driver = { |
1723 | .owner = THIS_MODULE, | 1773 | .owner = THIS_MODULE, |
1724 | .name = CTC_DRIVER_NAME, | 1774 | .name = CTC_DRIVER_NAME, |
@@ -1733,6 +1783,33 @@ static struct ccwgroup_driver ctcm_group_driver = { | |||
1733 | .restore = ctcm_pm_resume, | 1783 | .restore = ctcm_pm_resume, |
1734 | }; | 1784 | }; |
1735 | 1785 | ||
1786 | static ssize_t | ||
1787 | ctcm_driver_group_store(struct device_driver *ddrv, const char *buf, | ||
1788 | size_t count) | ||
1789 | { | ||
1790 | int err; | ||
1791 | |||
1792 | err = ccwgroup_create_from_string(ctcm_root_dev, | ||
1793 | ctcm_group_driver.driver_id, | ||
1794 | &ctcm_ccw_driver, 2, buf); | ||
1795 | return err ? err : count; | ||
1796 | } | ||
1797 | |||
1798 | static DRIVER_ATTR(group, 0200, NULL, ctcm_driver_group_store); | ||
1799 | |||
1800 | static struct attribute *ctcm_group_attrs[] = { | ||
1801 | &driver_attr_group.attr, | ||
1802 | NULL, | ||
1803 | }; | ||
1804 | |||
1805 | static struct attribute_group ctcm_group_attr_group = { | ||
1806 | .attrs = ctcm_group_attrs, | ||
1807 | }; | ||
1808 | |||
1809 | static const struct attribute_group *ctcm_group_attr_groups[] = { | ||
1810 | &ctcm_group_attr_group, | ||
1811 | NULL, | ||
1812 | }; | ||
1736 | 1813 | ||
1737 | /* | 1814 | /* |
1738 | * Module related routines | 1815 | * Module related routines |
@@ -1746,7 +1823,10 @@ static struct ccwgroup_driver ctcm_group_driver = { | |||
1746 | */ | 1823 | */ |
1747 | static void __exit ctcm_exit(void) | 1824 | static void __exit ctcm_exit(void) |
1748 | { | 1825 | { |
1749 | unregister_cu3088_discipline(&ctcm_group_driver); | 1826 | driver_remove_file(&ctcm_group_driver.driver, &driver_attr_group); |
1827 | ccwgroup_driver_unregister(&ctcm_group_driver); | ||
1828 | ccw_driver_unregister(&ctcm_ccw_driver); | ||
1829 | root_device_unregister(ctcm_root_dev); | ||
1750 | ctcm_unregister_dbf_views(); | 1830 | ctcm_unregister_dbf_views(); |
1751 | pr_info("CTCM driver unloaded\n"); | 1831 | pr_info("CTCM driver unloaded\n"); |
1752 | } | 1832 | } |
@@ -1772,17 +1852,31 @@ static int __init ctcm_init(void) | |||
1772 | channels = NULL; | 1852 | channels = NULL; |
1773 | 1853 | ||
1774 | ret = ctcm_register_dbf_views(); | 1854 | ret = ctcm_register_dbf_views(); |
1775 | if (ret) { | 1855 | if (ret) |
1776 | return ret; | 1856 | goto out_err; |
1777 | } | 1857 | ctcm_root_dev = root_device_register("ctcm"); |
1778 | ret = register_cu3088_discipline(&ctcm_group_driver); | 1858 | ret = IS_ERR(ctcm_root_dev) ? PTR_ERR(ctcm_root_dev) : 0; |
1779 | if (ret) { | 1859 | if (ret) |
1780 | ctcm_unregister_dbf_views(); | 1860 | goto register_err; |
1781 | pr_err("%s / register_cu3088_discipline failed, ret = %d\n", | 1861 | ret = ccw_driver_register(&ctcm_ccw_driver); |
1782 | __func__, ret); | 1862 | if (ret) |
1783 | return ret; | 1863 | goto ccw_err; |
1784 | } | 1864 | ctcm_group_driver.driver.groups = ctcm_group_attr_groups; |
1865 | ret = ccwgroup_driver_register(&ctcm_group_driver); | ||
1866 | if (ret) | ||
1867 | goto ccwgroup_err; | ||
1785 | print_banner(); | 1868 | print_banner(); |
1869 | return 0; | ||
1870 | |||
1871 | ccwgroup_err: | ||
1872 | ccw_driver_unregister(&ctcm_ccw_driver); | ||
1873 | ccw_err: | ||
1874 | root_device_unregister(ctcm_root_dev); | ||
1875 | register_err: | ||
1876 | ctcm_unregister_dbf_views(); | ||
1877 | out_err: | ||
1878 | pr_err("%s / Initializing the ctcm device driver failed, ret = %d\n", | ||
1879 | __func__, ret); | ||
1786 | return ret; | 1880 | return ret; |
1787 | } | 1881 | } |
1788 | 1882 | ||
diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index d925e732b7d8..d34fa14f44e7 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
17 | 17 | ||
18 | #include "fsm.h" | 18 | #include "fsm.h" |
19 | #include "cu3088.h" | ||
20 | #include "ctcm_dbug.h" | 19 | #include "ctcm_dbug.h" |
21 | #include "ctcm_mpc.h" | 20 | #include "ctcm_mpc.h" |
22 | 21 | ||
@@ -66,6 +65,23 @@ | |||
66 | ctcmpc_dumpit(buf, len); \ | 65 | ctcmpc_dumpit(buf, len); \ |
67 | } while (0) | 66 | } while (0) |
68 | 67 | ||
68 | /** | ||
69 | * Enum for classifying detected devices | ||
70 | */ | ||
71 | enum ctcm_channel_types { | ||
72 | /* Device is not a channel */ | ||
73 | ctcm_channel_type_none, | ||
74 | |||
75 | /* Device is a CTC/A */ | ||
76 | ctcm_channel_type_parallel, | ||
77 | |||
78 | /* Device is a FICON channel */ | ||
79 | ctcm_channel_type_ficon, | ||
80 | |||
81 | /* Device is a ESCON channel */ | ||
82 | ctcm_channel_type_escon | ||
83 | }; | ||
84 | |||
69 | /* | 85 | /* |
70 | * CCW commands, used in this driver. | 86 | * CCW commands, used in this driver. |
71 | */ | 87 | */ |
@@ -121,7 +137,7 @@ struct channel { | |||
121 | * Type of this channel. | 137 | * Type of this channel. |
122 | * CTC/A or Escon for valid channels. | 138 | * CTC/A or Escon for valid channels. |
123 | */ | 139 | */ |
124 | enum channel_types type; | 140 | enum ctcm_channel_types type; |
125 | /* | 141 | /* |
126 | * Misc. flags. See CHANNEL_FLAGS_... below | 142 | * Misc. flags. See CHANNEL_FLAGS_... below |
127 | */ | 143 | */ |
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index 781e18be7e8f..5978b390153f 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c | |||
@@ -53,7 +53,6 @@ | |||
53 | #include <linux/moduleparam.h> | 53 | #include <linux/moduleparam.h> |
54 | #include <asm/idals.h> | 54 | #include <asm/idals.h> |
55 | 55 | ||
56 | #include "cu3088.h" | ||
57 | #include "ctcm_mpc.h" | 56 | #include "ctcm_mpc.h" |
58 | #include "ctcm_main.h" | 57 | #include "ctcm_main.h" |
59 | #include "ctcm_fsms.h" | 58 | #include "ctcm_fsms.h" |
diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index 8452bb052d68..2b24550e865e 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
15 | 15 | ||
16 | #include <linux/sysfs.h> | 16 | #include <linux/sysfs.h> |
17 | #include <linux/slab.h> | ||
17 | #include "ctcm_main.h" | 18 | #include "ctcm_main.h" |
18 | 19 | ||
19 | /* | 20 | /* |
@@ -158,6 +159,15 @@ static ssize_t ctcm_proto_store(struct device *dev, | |||
158 | return count; | 159 | return count; |
159 | } | 160 | } |
160 | 161 | ||
162 | const char *ctcm_type[] = { | ||
163 | "not a channel", | ||
164 | "CTC/A", | ||
165 | "FICON channel", | ||
166 | "ESCON channel", | ||
167 | "unknown channel type", | ||
168 | "unsupported channel type", | ||
169 | }; | ||
170 | |||
161 | static ssize_t ctcm_type_show(struct device *dev, | 171 | static ssize_t ctcm_type_show(struct device *dev, |
162 | struct device_attribute *attr, char *buf) | 172 | struct device_attribute *attr, char *buf) |
163 | { | 173 | { |
@@ -168,7 +178,7 @@ static ssize_t ctcm_type_show(struct device *dev, | |||
168 | return -ENODEV; | 178 | return -ENODEV; |
169 | 179 | ||
170 | return sprintf(buf, "%s\n", | 180 | return sprintf(buf, "%s\n", |
171 | cu3088_type[cgdev->cdev[0]->id.driver_info]); | 181 | ctcm_type[cgdev->cdev[0]->id.driver_info]); |
172 | } | 182 | } |
173 | 183 | ||
174 | static DEVICE_ATTR(buffer, 0644, ctcm_buffer_show, ctcm_buffer_write); | 184 | static DEVICE_ATTR(buffer, 0644, ctcm_buffer_show, ctcm_buffer_write); |
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c deleted file mode 100644 index 48383459e99b..000000000000 --- a/drivers/s390/net/cu3088.c +++ /dev/null | |||
@@ -1,148 +0,0 @@ | |||
1 | /* | ||
2 | * CTC / LCS ccw_device driver | ||
3 | * | ||
4 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation | ||
5 | * Author(s): Arnd Bergmann <arndb@de.ibm.com> | ||
6 | * Cornelia Huck <cornelia.huck@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/err.h> | ||
27 | |||
28 | #include <asm/ccwdev.h> | ||
29 | #include <asm/ccwgroup.h> | ||
30 | |||
31 | #include "cu3088.h" | ||
32 | |||
33 | const char *cu3088_type[] = { | ||
34 | "not a channel", | ||
35 | "CTC/A", | ||
36 | "ESCON channel", | ||
37 | "FICON channel", | ||
38 | "OSA LCS card", | ||
39 | "CLAW channel device", | ||
40 | "unknown channel type", | ||
41 | "unsupported channel type", | ||
42 | }; | ||
43 | |||
44 | /* static definitions */ | ||
45 | |||
46 | static struct ccw_device_id cu3088_ids[] = { | ||
47 | { CCW_DEVICE(0x3088, 0x08), .driver_info = channel_type_parallel }, | ||
48 | { CCW_DEVICE(0x3088, 0x1f), .driver_info = channel_type_escon }, | ||
49 | { CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon }, | ||
50 | { CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 }, | ||
51 | { CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw }, | ||
52 | { /* end of list */ } | ||
53 | }; | ||
54 | |||
55 | static struct ccw_driver cu3088_driver; | ||
56 | |||
57 | static struct device *cu3088_root_dev; | ||
58 | |||
59 | static ssize_t | ||
60 | group_write(struct device_driver *drv, const char *buf, size_t count) | ||
61 | { | ||
62 | int ret; | ||
63 | struct ccwgroup_driver *cdrv; | ||
64 | |||
65 | cdrv = to_ccwgroupdrv(drv); | ||
66 | if (!cdrv) | ||
67 | return -EINVAL; | ||
68 | ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id, | ||
69 | &cu3088_driver, 2, buf); | ||
70 | |||
71 | return (ret == 0) ? count : ret; | ||
72 | } | ||
73 | |||
74 | static DRIVER_ATTR(group, 0200, NULL, group_write); | ||
75 | |||
76 | /* Register-unregister for ctc&lcs */ | ||
77 | int | ||
78 | register_cu3088_discipline(struct ccwgroup_driver *dcp) | ||
79 | { | ||
80 | int rc; | ||
81 | |||
82 | if (!dcp) | ||
83 | return -EINVAL; | ||
84 | |||
85 | /* Register discipline.*/ | ||
86 | rc = ccwgroup_driver_register(dcp); | ||
87 | if (rc) | ||
88 | return rc; | ||
89 | |||
90 | rc = driver_create_file(&dcp->driver, &driver_attr_group); | ||
91 | if (rc) | ||
92 | ccwgroup_driver_unregister(dcp); | ||
93 | |||
94 | return rc; | ||
95 | |||
96 | } | ||
97 | |||
98 | void | ||
99 | unregister_cu3088_discipline(struct ccwgroup_driver *dcp) | ||
100 | { | ||
101 | if (!dcp) | ||
102 | return; | ||
103 | |||
104 | driver_remove_file(&dcp->driver, &driver_attr_group); | ||
105 | ccwgroup_driver_unregister(dcp); | ||
106 | } | ||
107 | |||
108 | static struct ccw_driver cu3088_driver = { | ||
109 | .owner = THIS_MODULE, | ||
110 | .ids = cu3088_ids, | ||
111 | .name = "cu3088", | ||
112 | .probe = ccwgroup_probe_ccwdev, | ||
113 | .remove = ccwgroup_remove_ccwdev, | ||
114 | }; | ||
115 | |||
116 | /* module setup */ | ||
117 | static int __init | ||
118 | cu3088_init (void) | ||
119 | { | ||
120 | int rc; | ||
121 | |||
122 | cu3088_root_dev = root_device_register("cu3088"); | ||
123 | if (IS_ERR(cu3088_root_dev)) | ||
124 | return PTR_ERR(cu3088_root_dev); | ||
125 | rc = ccw_driver_register(&cu3088_driver); | ||
126 | if (rc) | ||
127 | root_device_unregister(cu3088_root_dev); | ||
128 | |||
129 | return rc; | ||
130 | } | ||
131 | |||
132 | static void __exit | ||
133 | cu3088_exit (void) | ||
134 | { | ||
135 | ccw_driver_unregister(&cu3088_driver); | ||
136 | root_device_unregister(cu3088_root_dev); | ||
137 | } | ||
138 | |||
139 | MODULE_DEVICE_TABLE(ccw,cu3088_ids); | ||
140 | MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); | ||
141 | MODULE_LICENSE("GPL"); | ||
142 | |||
143 | module_init(cu3088_init); | ||
144 | module_exit(cu3088_exit); | ||
145 | |||
146 | EXPORT_SYMBOL_GPL(cu3088_type); | ||
147 | EXPORT_SYMBOL_GPL(register_cu3088_discipline); | ||
148 | EXPORT_SYMBOL_GPL(unregister_cu3088_discipline); | ||
diff --git a/drivers/s390/net/cu3088.h b/drivers/s390/net/cu3088.h deleted file mode 100644 index d8558a7105a5..000000000000 --- a/drivers/s390/net/cu3088.h +++ /dev/null | |||
@@ -1,41 +0,0 @@ | |||
1 | #ifndef _CU3088_H | ||
2 | #define _CU3088_H | ||
3 | |||
4 | /** | ||
5 | * Enum for classifying detected devices. | ||
6 | */ | ||
7 | enum channel_types { | ||
8 | /* Device is not a channel */ | ||
9 | channel_type_none, | ||
10 | |||
11 | /* Device is a CTC/A */ | ||
12 | channel_type_parallel, | ||
13 | |||
14 | /* Device is a ESCON channel */ | ||
15 | channel_type_escon, | ||
16 | |||
17 | /* Device is a FICON channel */ | ||
18 | channel_type_ficon, | ||
19 | |||
20 | /* Device is a OSA2 card */ | ||
21 | channel_type_osa2, | ||
22 | |||
23 | /* Device is a CLAW channel device */ | ||
24 | channel_type_claw, | ||
25 | |||
26 | /* Device is a channel, but we don't know | ||
27 | * anything about it */ | ||
28 | channel_type_unknown, | ||
29 | |||
30 | /* Device is an unsupported model */ | ||
31 | channel_type_unsupported, | ||
32 | |||
33 | /* number of type entries */ | ||
34 | num_channel_types | ||
35 | }; | ||
36 | |||
37 | extern const char *cu3088_type[num_channel_types]; | ||
38 | extern int register_cu3088_discipline(struct ccwgroup_driver *); | ||
39 | extern void unregister_cu3088_discipline(struct ccwgroup_driver *); | ||
40 | |||
41 | #endif | ||
diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c index 2c1db8036b7c..e5dea67f902e 100644 --- a/drivers/s390/net/fsm.c +++ b/drivers/s390/net/fsm.c | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #include "fsm.h" | 6 | #include "fsm.h" |
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | #include <linux/slab.h> | ||
8 | #include <linux/timer.h> | 9 | #include <linux/timer.h> |
9 | 10 | ||
10 | MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); | 11 | MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); |
@@ -27,6 +28,7 @@ init_fsm(char *name, const char **state_names, const char **event_names, int nr_ | |||
27 | return NULL; | 28 | return NULL; |
28 | } | 29 | } |
29 | strlcpy(this->name, name, sizeof(this->name)); | 30 | strlcpy(this->name, name, sizeof(this->name)); |
31 | init_waitqueue_head(&this->wait_q); | ||
30 | 32 | ||
31 | f = kzalloc(sizeof(fsm), order); | 33 | f = kzalloc(sizeof(fsm), order); |
32 | if (f == NULL) { | 34 | if (f == NULL) { |
diff --git a/drivers/s390/net/fsm.h b/drivers/s390/net/fsm.h index af679c10f1bd..1e8b235d95b5 100644 --- a/drivers/s390/net/fsm.h +++ b/drivers/s390/net/fsm.h | |||
@@ -66,6 +66,7 @@ typedef struct fsm_instance_t { | |||
66 | char name[16]; | 66 | char name[16]; |
67 | void *userdata; | 67 | void *userdata; |
68 | int userint; | 68 | int userint; |
69 | wait_queue_head_t wait_q; | ||
69 | #if FSM_DEBUG_HISTORY | 70 | #if FSM_DEBUG_HISTORY |
70 | int history_index; | 71 | int history_index; |
71 | int history_size; | 72 | int history_size; |
@@ -197,6 +198,7 @@ fsm_newstate(fsm_instance *fi, int newstate) | |||
197 | printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name, | 198 | printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name, |
198 | fi->f->state_names[newstate]); | 199 | fi->f->state_names[newstate]); |
199 | #endif | 200 | #endif |
201 | wake_up(&fi->wait_q); | ||
200 | } | 202 | } |
201 | 203 | ||
202 | /** | 204 | /** |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index a70de9b4bf29..9b19ea13b4d8 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/igmp.h> | 37 | #include <linux/igmp.h> |
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/kthread.h> | 39 | #include <linux/kthread.h> |
40 | #include <linux/slab.h> | ||
40 | #include <net/arp.h> | 41 | #include <net/arp.h> |
41 | #include <net/ip.h> | 42 | #include <net/ip.h> |
42 | 43 | ||
@@ -47,7 +48,6 @@ | |||
47 | #include <asm/ccwgroup.h> | 48 | #include <asm/ccwgroup.h> |
48 | 49 | ||
49 | #include "lcs.h" | 50 | #include "lcs.h" |
50 | #include "cu3088.h" | ||
51 | 51 | ||
52 | 52 | ||
53 | #if !defined(CONFIG_NET_ETHERNET) && \ | 53 | #if !defined(CONFIG_NET_ETHERNET) && \ |
@@ -60,7 +60,11 @@ | |||
60 | */ | 60 | */ |
61 | 61 | ||
62 | static char version[] __initdata = "LCS driver"; | 62 | static char version[] __initdata = "LCS driver"; |
63 | static char debug_buffer[255]; | 63 | |
64 | /** | ||
65 | * the root device for lcs group devices | ||
66 | */ | ||
67 | static struct device *lcs_root_dev; | ||
64 | 68 | ||
65 | /** | 69 | /** |
66 | * Some prototypes. | 70 | * Some prototypes. |
@@ -76,6 +80,7 @@ static int lcs_recovery(void *ptr); | |||
76 | /** | 80 | /** |
77 | * Debug Facility Stuff | 81 | * Debug Facility Stuff |
78 | */ | 82 | */ |
83 | static char debug_buffer[255]; | ||
79 | static debug_info_t *lcs_dbf_setup; | 84 | static debug_info_t *lcs_dbf_setup; |
80 | static debug_info_t *lcs_dbf_trace; | 85 | static debug_info_t *lcs_dbf_trace; |
81 | 86 | ||
@@ -889,7 +894,7 @@ lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer, | |||
889 | rc = lcs_ready_buffer(&card->write, buffer); | 894 | rc = lcs_ready_buffer(&card->write, buffer); |
890 | if (rc) | 895 | if (rc) |
891 | return rc; | 896 | return rc; |
892 | init_timer(&timer); | 897 | init_timer_on_stack(&timer); |
893 | timer.function = lcs_lancmd_timeout; | 898 | timer.function = lcs_lancmd_timeout; |
894 | timer.data = (unsigned long) reply; | 899 | timer.data = (unsigned long) reply; |
895 | timer.expires = jiffies + HZ*card->lancmd_timeout; | 900 | timer.expires = jiffies + HZ*card->lancmd_timeout; |
@@ -1968,6 +1973,15 @@ lcs_portno_store (struct device *dev, struct device_attribute *attr, const char | |||
1968 | 1973 | ||
1969 | static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store); | 1974 | static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store); |
1970 | 1975 | ||
1976 | const char *lcs_type[] = { | ||
1977 | "not a channel", | ||
1978 | "2216 parallel", | ||
1979 | "2216 channel", | ||
1980 | "OSA LCS card", | ||
1981 | "unknown channel type", | ||
1982 | "unsupported channel type", | ||
1983 | }; | ||
1984 | |||
1971 | static ssize_t | 1985 | static ssize_t |
1972 | lcs_type_show(struct device *dev, struct device_attribute *attr, char *buf) | 1986 | lcs_type_show(struct device *dev, struct device_attribute *attr, char *buf) |
1973 | { | 1987 | { |
@@ -1977,7 +1991,7 @@ lcs_type_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
1977 | if (!cgdev) | 1991 | if (!cgdev) |
1978 | return -ENODEV; | 1992 | return -ENODEV; |
1979 | 1993 | ||
1980 | return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]); | 1994 | return sprintf(buf, "%s\n", lcs_type[cgdev->cdev[0]->id.driver_info]); |
1981 | } | 1995 | } |
1982 | 1996 | ||
1983 | static DEVICE_ATTR(type, 0444, lcs_type_show, NULL); | 1997 | static DEVICE_ATTR(type, 0444, lcs_type_show, NULL); |
@@ -2130,8 +2144,12 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) | |||
2130 | card->write.ccwdev = ccwgdev->cdev[1]; | 2144 | card->write.ccwdev = ccwgdev->cdev[1]; |
2131 | 2145 | ||
2132 | recover_state = card->state; | 2146 | recover_state = card->state; |
2133 | ccw_device_set_online(card->read.ccwdev); | 2147 | rc = ccw_device_set_online(card->read.ccwdev); |
2134 | ccw_device_set_online(card->write.ccwdev); | 2148 | if (rc) |
2149 | goto out_err; | ||
2150 | rc = ccw_device_set_online(card->write.ccwdev); | ||
2151 | if (rc) | ||
2152 | goto out_werr; | ||
2135 | 2153 | ||
2136 | LCS_DBF_TEXT(3, setup, "lcsnewdv"); | 2154 | LCS_DBF_TEXT(3, setup, "lcsnewdv"); |
2137 | 2155 | ||
@@ -2210,8 +2228,10 @@ netdev_out: | |||
2210 | return 0; | 2228 | return 0; |
2211 | out: | 2229 | out: |
2212 | 2230 | ||
2213 | ccw_device_set_offline(card->read.ccwdev); | ||
2214 | ccw_device_set_offline(card->write.ccwdev); | 2231 | ccw_device_set_offline(card->write.ccwdev); |
2232 | out_werr: | ||
2233 | ccw_device_set_offline(card->read.ccwdev); | ||
2234 | out_err: | ||
2215 | return -ENODEV; | 2235 | return -ENODEV; |
2216 | } | 2236 | } |
2217 | 2237 | ||
@@ -2364,6 +2384,22 @@ static int lcs_restore(struct ccwgroup_device *gdev) | |||
2364 | return lcs_pm_resume(card); | 2384 | return lcs_pm_resume(card); |
2365 | } | 2385 | } |
2366 | 2386 | ||
2387 | static struct ccw_device_id lcs_ids[] = { | ||
2388 | {CCW_DEVICE(0x3088, 0x08), .driver_info = lcs_channel_type_parallel}, | ||
2389 | {CCW_DEVICE(0x3088, 0x1f), .driver_info = lcs_channel_type_2216}, | ||
2390 | {CCW_DEVICE(0x3088, 0x60), .driver_info = lcs_channel_type_osa2}, | ||
2391 | {}, | ||
2392 | }; | ||
2393 | MODULE_DEVICE_TABLE(ccw, lcs_ids); | ||
2394 | |||
2395 | static struct ccw_driver lcs_ccw_driver = { | ||
2396 | .owner = THIS_MODULE, | ||
2397 | .name = "lcs", | ||
2398 | .ids = lcs_ids, | ||
2399 | .probe = ccwgroup_probe_ccwdev, | ||
2400 | .remove = ccwgroup_remove_ccwdev, | ||
2401 | }; | ||
2402 | |||
2367 | /** | 2403 | /** |
2368 | * LCS ccwgroup driver registration | 2404 | * LCS ccwgroup driver registration |
2369 | */ | 2405 | */ |
@@ -2383,6 +2419,33 @@ static struct ccwgroup_driver lcs_group_driver = { | |||
2383 | .restore = lcs_restore, | 2419 | .restore = lcs_restore, |
2384 | }; | 2420 | }; |
2385 | 2421 | ||
2422 | static ssize_t | ||
2423 | lcs_driver_group_store(struct device_driver *ddrv, const char *buf, | ||
2424 | size_t count) | ||
2425 | { | ||
2426 | int err; | ||
2427 | err = ccwgroup_create_from_string(lcs_root_dev, | ||
2428 | lcs_group_driver.driver_id, | ||
2429 | &lcs_ccw_driver, 2, buf); | ||
2430 | return err ? err : count; | ||
2431 | } | ||
2432 | |||
2433 | static DRIVER_ATTR(group, 0200, NULL, lcs_driver_group_store); | ||
2434 | |||
2435 | static struct attribute *lcs_group_attrs[] = { | ||
2436 | &driver_attr_group.attr, | ||
2437 | NULL, | ||
2438 | }; | ||
2439 | |||
2440 | static struct attribute_group lcs_group_attr_group = { | ||
2441 | .attrs = lcs_group_attrs, | ||
2442 | }; | ||
2443 | |||
2444 | static const struct attribute_group *lcs_group_attr_groups[] = { | ||
2445 | &lcs_group_attr_group, | ||
2446 | NULL, | ||
2447 | }; | ||
2448 | |||
2386 | /** | 2449 | /** |
2387 | * LCS Module/Kernel initialization function | 2450 | * LCS Module/Kernel initialization function |
2388 | */ | 2451 | */ |
@@ -2394,17 +2457,30 @@ __init lcs_init_module(void) | |||
2394 | pr_info("Loading %s\n", version); | 2457 | pr_info("Loading %s\n", version); |
2395 | rc = lcs_register_debug_facility(); | 2458 | rc = lcs_register_debug_facility(); |
2396 | LCS_DBF_TEXT(0, setup, "lcsinit"); | 2459 | LCS_DBF_TEXT(0, setup, "lcsinit"); |
2397 | if (rc) { | 2460 | if (rc) |
2398 | pr_err("Initialization failed\n"); | 2461 | goto out_err; |
2399 | return rc; | 2462 | lcs_root_dev = root_device_register("lcs"); |
2400 | } | 2463 | rc = IS_ERR(lcs_root_dev) ? PTR_ERR(lcs_root_dev) : 0; |
2401 | 2464 | if (rc) | |
2402 | rc = register_cu3088_discipline(&lcs_group_driver); | 2465 | goto register_err; |
2403 | if (rc) { | 2466 | rc = ccw_driver_register(&lcs_ccw_driver); |
2404 | pr_err("Initialization failed\n"); | 2467 | if (rc) |
2405 | return rc; | 2468 | goto ccw_err; |
2406 | } | 2469 | lcs_group_driver.driver.groups = lcs_group_attr_groups; |
2470 | rc = ccwgroup_driver_register(&lcs_group_driver); | ||
2471 | if (rc) | ||
2472 | goto ccwgroup_err; | ||
2407 | return 0; | 2473 | return 0; |
2474 | |||
2475 | ccwgroup_err: | ||
2476 | ccw_driver_unregister(&lcs_ccw_driver); | ||
2477 | ccw_err: | ||
2478 | root_device_unregister(lcs_root_dev); | ||
2479 | register_err: | ||
2480 | lcs_unregister_debug_facility(); | ||
2481 | out_err: | ||
2482 | pr_err("Initializing the lcs device driver failed\n"); | ||
2483 | return rc; | ||
2408 | } | 2484 | } |
2409 | 2485 | ||
2410 | 2486 | ||
@@ -2416,7 +2492,11 @@ __exit lcs_cleanup_module(void) | |||
2416 | { | 2492 | { |
2417 | pr_info("Terminating lcs module.\n"); | 2493 | pr_info("Terminating lcs module.\n"); |
2418 | LCS_DBF_TEXT(0, trace, "cleanup"); | 2494 | LCS_DBF_TEXT(0, trace, "cleanup"); |
2419 | unregister_cu3088_discipline(&lcs_group_driver); | 2495 | driver_remove_file(&lcs_group_driver.driver, |
2496 | &driver_attr_group); | ||
2497 | ccwgroup_driver_unregister(&lcs_group_driver); | ||
2498 | ccw_driver_unregister(&lcs_ccw_driver); | ||
2499 | root_device_unregister(lcs_root_dev); | ||
2420 | lcs_unregister_debug_facility(); | 2500 | lcs_unregister_debug_facility(); |
2421 | } | 2501 | } |
2422 | 2502 | ||
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index 6d668642af27..8c03392ac833 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h | |||
@@ -36,6 +36,24 @@ static inline int lcs_dbf_passes(debug_info_t *dbf_grp, int level) | |||
36 | #define CARD_FROM_DEV(cdev) \ | 36 | #define CARD_FROM_DEV(cdev) \ |
37 | (struct lcs_card *) dev_get_drvdata( \ | 37 | (struct lcs_card *) dev_get_drvdata( \ |
38 | &((struct ccwgroup_device *)dev_get_drvdata(&cdev->dev))->dev); | 38 | &((struct ccwgroup_device *)dev_get_drvdata(&cdev->dev))->dev); |
39 | |||
40 | /** | ||
41 | * Enum for classifying detected devices. | ||
42 | */ | ||
43 | enum lcs_channel_types { | ||
44 | /* Device is not a channel */ | ||
45 | lcs_channel_type_none, | ||
46 | |||
47 | /* Device is a 2216 channel */ | ||
48 | lcs_channel_type_parallel, | ||
49 | |||
50 | /* Device is a 2216 channel */ | ||
51 | lcs_channel_type_2216, | ||
52 | |||
53 | /* Device is a OSA2 card */ | ||
54 | lcs_channel_type_osa2 | ||
55 | }; | ||
56 | |||
39 | /** | 57 | /** |
40 | * CCW commands used in this driver | 58 | * CCW commands used in this driver |
41 | */ | 59 | */ |
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index c84eadd3602a..65ebee0a3266 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -113,11 +113,9 @@ static inline int iucv_dbf_passes(debug_info_t *dbf_grp, int level) | |||
113 | #define IUCV_DBF_TEXT_(name, level, text...) \ | 113 | #define IUCV_DBF_TEXT_(name, level, text...) \ |
114 | do { \ | 114 | do { \ |
115 | if (iucv_dbf_passes(iucv_dbf_##name, level)) { \ | 115 | if (iucv_dbf_passes(iucv_dbf_##name, level)) { \ |
116 | char* iucv_dbf_txt_buf = \ | 116 | char* __buf = get_cpu_var(iucv_dbf_txt_buf); \ |
117 | get_cpu_var(iucv_dbf_txt_buf); \ | 117 | sprintf(__buf, text); \ |
118 | sprintf(iucv_dbf_txt_buf, text); \ | 118 | debug_text_event(iucv_dbf_##name, level, __buf); \ |
119 | debug_text_event(iucv_dbf_##name, level, \ | ||
120 | iucv_dbf_txt_buf); \ | ||
121 | put_cpu_var(iucv_dbf_txt_buf); \ | 119 | put_cpu_var(iucv_dbf_txt_buf); \ |
122 | } \ | 120 | } \ |
123 | } while (0) | 121 | } while (0) |
@@ -161,7 +159,7 @@ static void netiucv_pm_complete(struct device *); | |||
161 | static int netiucv_pm_freeze(struct device *); | 159 | static int netiucv_pm_freeze(struct device *); |
162 | static int netiucv_pm_restore_thaw(struct device *); | 160 | static int netiucv_pm_restore_thaw(struct device *); |
163 | 161 | ||
164 | static struct dev_pm_ops netiucv_pm_ops = { | 162 | static const struct dev_pm_ops netiucv_pm_ops = { |
165 | .prepare = netiucv_pm_prepare, | 163 | .prepare = netiucv_pm_prepare, |
166 | .complete = netiucv_pm_complete, | 164 | .complete = netiucv_pm_complete, |
167 | .freeze = netiucv_pm_freeze, | 165 | .freeze = netiucv_pm_freeze, |
@@ -741,13 +739,13 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) | |||
741 | if (single_flag) { | 739 | if (single_flag) { |
742 | if ((skb = skb_dequeue(&conn->commit_queue))) { | 740 | if ((skb = skb_dequeue(&conn->commit_queue))) { |
743 | atomic_dec(&skb->users); | 741 | atomic_dec(&skb->users); |
744 | dev_kfree_skb_any(skb); | ||
745 | if (privptr) { | 742 | if (privptr) { |
746 | privptr->stats.tx_packets++; | 743 | privptr->stats.tx_packets++; |
747 | privptr->stats.tx_bytes += | 744 | privptr->stats.tx_bytes += |
748 | (skb->len - NETIUCV_HDRLEN | 745 | (skb->len - NETIUCV_HDRLEN |
749 | - NETIUCV_HDRLEN); | 746 | - NETIUCV_HDRLEN); |
750 | } | 747 | } |
748 | dev_kfree_skb_any(skb); | ||
751 | } | 749 | } |
752 | } | 750 | } |
753 | conn->tx_buff->data = conn->tx_buff->head; | 751 | conn->tx_buff->data = conn->tx_buff->head; |
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 31a2b4e502ce..fcd005aad989 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -122,7 +122,6 @@ struct qeth_perf_stats { | |||
122 | __u64 outbound_do_qdio_start_time; | 122 | __u64 outbound_do_qdio_start_time; |
123 | unsigned int outbound_do_qdio_cnt; | 123 | unsigned int outbound_do_qdio_cnt; |
124 | unsigned int outbound_do_qdio_time; | 124 | unsigned int outbound_do_qdio_time; |
125 | /* eddp data */ | ||
126 | unsigned int large_send_bytes; | 125 | unsigned int large_send_bytes; |
127 | unsigned int large_send_cnt; | 126 | unsigned int large_send_cnt; |
128 | unsigned int sg_skbs_sent; | 127 | unsigned int sg_skbs_sent; |
@@ -135,6 +134,7 @@ struct qeth_perf_stats { | |||
135 | unsigned int sg_frags_rx; | 134 | unsigned int sg_frags_rx; |
136 | unsigned int sg_alloc_page_rx; | 135 | unsigned int sg_alloc_page_rx; |
137 | unsigned int tx_csum; | 136 | unsigned int tx_csum; |
137 | unsigned int tx_lin; | ||
138 | }; | 138 | }; |
139 | 139 | ||
140 | /* Routing stuff */ | 140 | /* Routing stuff */ |
@@ -648,6 +648,8 @@ struct qeth_card_options { | |||
648 | enum qeth_large_send_types large_send; | 648 | enum qeth_large_send_types large_send; |
649 | int performance_stats; | 649 | int performance_stats; |
650 | int rx_sg_cb; | 650 | int rx_sg_cb; |
651 | enum qeth_ipa_isolation_modes isolation; | ||
652 | int sniffer; | ||
651 | }; | 653 | }; |
652 | 654 | ||
653 | /* | 655 | /* |
@@ -736,6 +738,7 @@ struct qeth_card { | |||
736 | struct qeth_discipline discipline; | 738 | struct qeth_discipline discipline; |
737 | atomic_t force_alloc_skb; | 739 | atomic_t force_alloc_skb; |
738 | struct service_level qeth_service_level; | 740 | struct service_level qeth_service_level; |
741 | struct qdio_ssqd_desc ssqd; | ||
739 | }; | 742 | }; |
740 | 743 | ||
741 | struct qeth_card_list_struct { | 744 | struct qeth_card_list_struct { |
@@ -760,7 +763,8 @@ static inline int qeth_get_micros(void) | |||
760 | 763 | ||
761 | static inline int qeth_get_ip_version(struct sk_buff *skb) | 764 | static inline int qeth_get_ip_version(struct sk_buff *skb) |
762 | { | 765 | { |
763 | switch (skb->protocol) { | 766 | struct ethhdr *ehdr = (struct ethhdr *)skb->data; |
767 | switch (ehdr->h_proto) { | ||
764 | case ETH_P_IPV6: | 768 | case ETH_P_IPV6: |
765 | return 6; | 769 | return 6; |
766 | case ETH_P_IP: | 770 | case ETH_P_IP: |
@@ -776,7 +780,6 @@ static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, | |||
776 | list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list); | 780 | list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list); |
777 | } | 781 | } |
778 | 782 | ||
779 | struct qeth_eddp_context; | ||
780 | extern struct ccwgroup_driver qeth_l2_ccwgroup_driver; | 783 | extern struct ccwgroup_driver qeth_l2_ccwgroup_driver; |
781 | extern struct ccwgroup_driver qeth_l3_ccwgroup_driver; | 784 | extern struct ccwgroup_driver qeth_l3_ccwgroup_driver; |
782 | const char *qeth_get_cardname_short(struct qeth_card *); | 785 | const char *qeth_get_cardname_short(struct qeth_card *); |
@@ -811,7 +814,8 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, | |||
811 | struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, | 814 | struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, |
812 | enum qeth_ipa_cmds, enum qeth_prot_versions); | 815 | enum qeth_ipa_cmds, enum qeth_prot_versions); |
813 | int qeth_query_setadapterparms(struct qeth_card *); | 816 | int qeth_query_setadapterparms(struct qeth_card *); |
814 | int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, const char *); | 817 | int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *, |
818 | unsigned int, const char *); | ||
815 | void qeth_queue_input_buffer(struct qeth_card *, int); | 819 | void qeth_queue_input_buffer(struct qeth_card *, int); |
816 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, | 820 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, |
817 | struct qdio_buffer *, struct qdio_buffer_element **, int *, | 821 | struct qdio_buffer *, struct qdio_buffer_element **, int *, |
@@ -836,7 +840,6 @@ void qeth_prepare_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, char); | |||
836 | struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *); | 840 | struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *); |
837 | int qeth_mdio_read(struct net_device *, int, int); | 841 | int qeth_mdio_read(struct net_device *, int, int); |
838 | int qeth_snmp_command(struct qeth_card *, char __user *); | 842 | int qeth_snmp_command(struct qeth_card *, char __user *); |
839 | int qeth_set_large_send(struct qeth_card *, enum qeth_large_send_types); | ||
840 | struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32); | 843 | struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32); |
841 | int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *, | 844 | int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *, |
842 | unsigned long); | 845 | unsigned long); |
@@ -849,13 +852,14 @@ int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, | |||
849 | struct sk_buff *, struct qeth_hdr *, int, int, int); | 852 | struct sk_buff *, struct qeth_hdr *, int, int, int); |
850 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, | 853 | int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, |
851 | struct sk_buff *, struct qeth_hdr *, int); | 854 | struct sk_buff *, struct qeth_hdr *, int); |
852 | int qeth_core_get_stats_count(struct net_device *); | 855 | int qeth_core_get_sset_count(struct net_device *, int); |
853 | void qeth_core_get_ethtool_stats(struct net_device *, | 856 | void qeth_core_get_ethtool_stats(struct net_device *, |
854 | struct ethtool_stats *, u64 *); | 857 | struct ethtool_stats *, u64 *); |
855 | void qeth_core_get_strings(struct net_device *, u32, u8 *); | 858 | void qeth_core_get_strings(struct net_device *, u32, u8 *); |
856 | void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); | 859 | void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); |
857 | void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...); | 860 | void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...); |
858 | int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); | 861 | int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); |
862 | int qeth_set_access_ctrl_online(struct qeth_card *card); | ||
859 | 863 | ||
860 | /* exports for OSN */ | 864 | /* exports for OSN */ |
861 | int qeth_osn_assist(struct net_device *, void *, int); | 865 | int qeth_osn_assist(struct net_device *, void *, int); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c4a42d970158..3ba738b2e271 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/tcp.h> | 20 | #include <linux/tcp.h> |
21 | #include <linux/mii.h> | 21 | #include <linux/mii.h> |
22 | #include <linux/kthread.h> | 22 | #include <linux/kthread.h> |
23 | #include <linux/slab.h> | ||
23 | 24 | ||
24 | #include <asm/ebcdic.h> | 25 | #include <asm/ebcdic.h> |
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -269,41 +270,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt) | |||
269 | card->qdio.init_pool.buf_count = bufcnt; | 270 | card->qdio.init_pool.buf_count = bufcnt; |
270 | return qeth_alloc_buffer_pool(card); | 271 | return qeth_alloc_buffer_pool(card); |
271 | } | 272 | } |
272 | 273 | EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); | |
273 | int qeth_set_large_send(struct qeth_card *card, | ||
274 | enum qeth_large_send_types type) | ||
275 | { | ||
276 | int rc = 0; | ||
277 | |||
278 | if (card->dev == NULL) { | ||
279 | card->options.large_send = type; | ||
280 | return 0; | ||
281 | } | ||
282 | if (card->state == CARD_STATE_UP) | ||
283 | netif_tx_disable(card->dev); | ||
284 | card->options.large_send = type; | ||
285 | switch (card->options.large_send) { | ||
286 | case QETH_LARGE_SEND_TSO: | ||
287 | if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { | ||
288 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG | | ||
289 | NETIF_F_HW_CSUM; | ||
290 | } else { | ||
291 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
292 | NETIF_F_HW_CSUM); | ||
293 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
294 | rc = -EOPNOTSUPP; | ||
295 | } | ||
296 | break; | ||
297 | default: /* includes QETH_LARGE_SEND_NO */ | ||
298 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
299 | NETIF_F_HW_CSUM); | ||
300 | break; | ||
301 | } | ||
302 | if (card->state == CARD_STATE_UP) | ||
303 | netif_wake_queue(card->dev); | ||
304 | return rc; | ||
305 | } | ||
306 | EXPORT_SYMBOL_GPL(qeth_set_large_send); | ||
307 | 274 | ||
308 | static int qeth_issue_next_read(struct qeth_card *card) | 275 | static int qeth_issue_next_read(struct qeth_card *card) |
309 | { | 276 | { |
@@ -385,8 +352,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, | |||
385 | if (IS_IPA(iob->data)) { | 352 | if (IS_IPA(iob->data)) { |
386 | cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); | 353 | cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); |
387 | if (IS_IPA_REPLY(cmd)) { | 354 | if (IS_IPA_REPLY(cmd)) { |
388 | if (cmd->hdr.command < IPA_CMD_SETCCID || | 355 | if (cmd->hdr.command != IPA_CMD_SETCCID && |
389 | cmd->hdr.command > IPA_CMD_MODCCID) | 356 | cmd->hdr.command != IPA_CMD_DELCCID && |
357 | cmd->hdr.command != IPA_CMD_MODCCID && | ||
358 | cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) | ||
390 | qeth_issue_ipa_msg(cmd, | 359 | qeth_issue_ipa_msg(cmd, |
391 | cmd->hdr.return_code, card); | 360 | cmd->hdr.return_code, card); |
392 | return cmd; | 361 | return cmd; |
@@ -569,7 +538,8 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel, | |||
569 | dev_err(&card->gdev->dev, | 538 | dev_err(&card->gdev->dev, |
570 | "The qeth device is not configured " | 539 | "The qeth device is not configured " |
571 | "for the OSI layer required by z/VM\n"); | 540 | "for the OSI layer required by z/VM\n"); |
572 | qeth_schedule_recovery(card); | 541 | else |
542 | qeth_schedule_recovery(card); | ||
573 | goto out; | 543 | goto out; |
574 | } | 544 | } |
575 | 545 | ||
@@ -1079,6 +1049,7 @@ static void qeth_set_intial_options(struct qeth_card *card) | |||
1079 | card->options.add_hhlen = DEFAULT_ADD_HHLEN; | 1049 | card->options.add_hhlen = DEFAULT_ADD_HHLEN; |
1080 | card->options.performance_stats = 0; | 1050 | card->options.performance_stats = 0; |
1081 | card->options.rx_sg_cb = QETH_RX_SG_CB; | 1051 | card->options.rx_sg_cb = QETH_RX_SG_CB; |
1052 | card->options.isolation = ISOLATION_MODE_NONE; | ||
1082 | } | 1053 | } |
1083 | 1054 | ||
1084 | static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread) | 1055 | static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread) |
@@ -1134,11 +1105,6 @@ static int qeth_setup_card(struct qeth_card *card) | |||
1134 | card->thread_running_mask = 0; | 1105 | card->thread_running_mask = 0; |
1135 | INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); | 1106 | INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); |
1136 | INIT_LIST_HEAD(&card->ip_list); | 1107 | INIT_LIST_HEAD(&card->ip_list); |
1137 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); | ||
1138 | if (!card->ip_tbd_list) { | ||
1139 | QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); | ||
1140 | return -ENOMEM; | ||
1141 | } | ||
1142 | INIT_LIST_HEAD(card->ip_tbd_list); | 1108 | INIT_LIST_HEAD(card->ip_tbd_list); |
1143 | INIT_LIST_HEAD(&card->cmd_waiter_list); | 1109 | INIT_LIST_HEAD(&card->cmd_waiter_list); |
1144 | init_waitqueue_head(&card->wait_q); | 1110 | init_waitqueue_head(&card->wait_q); |
@@ -1149,8 +1115,6 @@ static int qeth_setup_card(struct qeth_card *card) | |||
1149 | card->ipato.enabled = 0; | 1115 | card->ipato.enabled = 0; |
1150 | card->ipato.invert4 = 0; | 1116 | card->ipato.invert4 = 0; |
1151 | card->ipato.invert6 = 0; | 1117 | card->ipato.invert6 = 0; |
1152 | if (card->info.type == QETH_CARD_TYPE_IQD) | ||
1153 | card->options.checksum_type = NO_CHECKSUMMING; | ||
1154 | /* init QDIO stuff */ | 1118 | /* init QDIO stuff */ |
1155 | qeth_init_qdio_info(card); | 1119 | qeth_init_qdio_info(card); |
1156 | return 0; | 1120 | return 0; |
@@ -1172,21 +1136,30 @@ static struct qeth_card *qeth_alloc_card(void) | |||
1172 | QETH_DBF_TEXT(SETUP, 2, "alloccrd"); | 1136 | QETH_DBF_TEXT(SETUP, 2, "alloccrd"); |
1173 | card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL); | 1137 | card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL); |
1174 | if (!card) | 1138 | if (!card) |
1175 | return NULL; | 1139 | goto out; |
1176 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 1140 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
1177 | if (qeth_setup_channel(&card->read)) { | 1141 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); |
1178 | kfree(card); | 1142 | if (!card->ip_tbd_list) { |
1179 | return NULL; | 1143 | QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); |
1180 | } | 1144 | goto out_card; |
1181 | if (qeth_setup_channel(&card->write)) { | ||
1182 | qeth_clean_channel(&card->read); | ||
1183 | kfree(card); | ||
1184 | return NULL; | ||
1185 | } | 1145 | } |
1146 | if (qeth_setup_channel(&card->read)) | ||
1147 | goto out_ip; | ||
1148 | if (qeth_setup_channel(&card->write)) | ||
1149 | goto out_channel; | ||
1186 | card->options.layer2 = -1; | 1150 | card->options.layer2 = -1; |
1187 | card->qeth_service_level.seq_print = qeth_core_sl_print; | 1151 | card->qeth_service_level.seq_print = qeth_core_sl_print; |
1188 | register_service_level(&card->qeth_service_level); | 1152 | register_service_level(&card->qeth_service_level); |
1189 | return card; | 1153 | return card; |
1154 | |||
1155 | out_channel: | ||
1156 | qeth_clean_channel(&card->read); | ||
1157 | out_ip: | ||
1158 | kfree(card->ip_tbd_list); | ||
1159 | out_card: | ||
1160 | kfree(card); | ||
1161 | out: | ||
1162 | return NULL; | ||
1190 | } | 1163 | } |
1191 | 1164 | ||
1192 | static int qeth_determine_card_type(struct qeth_card *card) | 1165 | static int qeth_determine_card_type(struct qeth_card *card) |
@@ -1389,26 +1362,29 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer, | |||
1389 | return ret; | 1362 | return ret; |
1390 | } | 1363 | } |
1391 | 1364 | ||
1392 | static int qeth_get_unitaddr(struct qeth_card *card) | 1365 | static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) |
1393 | { | 1366 | { |
1394 | int length; | 1367 | QETH_DBF_TEXT(SETUP, 2, "cfgunit"); |
1395 | char *prcd; | ||
1396 | int rc; | ||
1397 | |||
1398 | QETH_DBF_TEXT(SETUP, 2, "getunit"); | ||
1399 | rc = qeth_read_conf_data(card, (void **) &prcd, &length); | ||
1400 | if (rc) { | ||
1401 | QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", | ||
1402 | dev_name(&card->gdev->dev), rc); | ||
1403 | return rc; | ||
1404 | } | ||
1405 | card->info.chpid = prcd[30]; | 1368 | card->info.chpid = prcd[30]; |
1406 | card->info.unit_addr2 = prcd[31]; | 1369 | card->info.unit_addr2 = prcd[31]; |
1407 | card->info.cula = prcd[63]; | 1370 | card->info.cula = prcd[63]; |
1408 | card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && | 1371 | card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && |
1409 | (prcd[0x11] == _ascebc['M'])); | 1372 | (prcd[0x11] == _ascebc['M'])); |
1410 | kfree(prcd); | 1373 | } |
1411 | return 0; | 1374 | |
1375 | static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd) | ||
1376 | { | ||
1377 | QETH_DBF_TEXT(SETUP, 2, "cfgblkt"); | ||
1378 | |||
1379 | if (prcd[74] == 0xF0 && prcd[75] == 0xF0 && prcd[76] == 0xF5) { | ||
1380 | card->info.blkt.time_total = 250; | ||
1381 | card->info.blkt.inter_packet = 5; | ||
1382 | card->info.blkt.inter_packet_jumbo = 15; | ||
1383 | } else { | ||
1384 | card->info.blkt.time_total = 0; | ||
1385 | card->info.blkt.inter_packet = 0; | ||
1386 | card->info.blkt.inter_packet_jumbo = 0; | ||
1387 | } | ||
1412 | } | 1388 | } |
1413 | 1389 | ||
1414 | static void qeth_init_tokens(struct qeth_card *card) | 1390 | static void qeth_init_tokens(struct qeth_card *card) |
@@ -2607,8 +2583,8 @@ int qeth_query_setadapterparms(struct qeth_card *card) | |||
2607 | } | 2583 | } |
2608 | EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); | 2584 | EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); |
2609 | 2585 | ||
2610 | int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, | 2586 | int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf, |
2611 | const char *dbftext) | 2587 | unsigned int qdio_error, const char *dbftext) |
2612 | { | 2588 | { |
2613 | if (qdio_error) { | 2589 | if (qdio_error) { |
2614 | QETH_DBF_TEXT(TRACE, 2, dbftext); | 2590 | QETH_DBF_TEXT(TRACE, 2, dbftext); |
@@ -2618,7 +2594,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, | |||
2618 | QETH_DBF_TEXT_(QERR, 2, " F14=%02X", | 2594 | QETH_DBF_TEXT_(QERR, 2, " F14=%02X", |
2619 | buf->element[14].flags & 0xff); | 2595 | buf->element[14].flags & 0xff); |
2620 | QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error); | 2596 | QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error); |
2621 | return 1; | 2597 | if ((buf->element[15].flags & 0xff) == 0x12) { |
2598 | card->stats.rx_dropped++; | ||
2599 | return 0; | ||
2600 | } else | ||
2601 | return 1; | ||
2622 | } | 2602 | } |
2623 | return 0; | 2603 | return 0; |
2624 | } | 2604 | } |
@@ -2701,7 +2681,7 @@ static int qeth_handle_send_error(struct qeth_card *card, | |||
2701 | qdio_err = 1; | 2681 | qdio_err = 1; |
2702 | } | 2682 | } |
2703 | } | 2683 | } |
2704 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); | 2684 | qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr"); |
2705 | 2685 | ||
2706 | if (!qdio_err) | 2686 | if (!qdio_err) |
2707 | return QETH_SEND_ERROR_NONE; | 2687 | return QETH_SEND_ERROR_NONE; |
@@ -3389,10 +3369,161 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card) | |||
3389 | } | 3369 | } |
3390 | EXPORT_SYMBOL_GPL(qeth_setadpparms_change_macaddr); | 3370 | EXPORT_SYMBOL_GPL(qeth_setadpparms_change_macaddr); |
3391 | 3371 | ||
3372 | static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card, | ||
3373 | struct qeth_reply *reply, unsigned long data) | ||
3374 | { | ||
3375 | struct qeth_ipa_cmd *cmd; | ||
3376 | struct qeth_set_access_ctrl *access_ctrl_req; | ||
3377 | int rc; | ||
3378 | |||
3379 | QETH_DBF_TEXT(TRACE, 4, "setaccb"); | ||
3380 | |||
3381 | cmd = (struct qeth_ipa_cmd *) data; | ||
3382 | access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; | ||
3383 | QETH_DBF_TEXT_(SETUP, 2, "setaccb"); | ||
3384 | QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name); | ||
3385 | QETH_DBF_TEXT_(SETUP, 2, "rc=%d", | ||
3386 | cmd->data.setadapterparms.hdr.return_code); | ||
3387 | switch (cmd->data.setadapterparms.hdr.return_code) { | ||
3388 | case SET_ACCESS_CTRL_RC_SUCCESS: | ||
3389 | case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED: | ||
3390 | case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED: | ||
3391 | { | ||
3392 | card->options.isolation = access_ctrl_req->subcmd_code; | ||
3393 | if (card->options.isolation == ISOLATION_MODE_NONE) { | ||
3394 | dev_info(&card->gdev->dev, | ||
3395 | "QDIO data connection isolation is deactivated\n"); | ||
3396 | } else { | ||
3397 | dev_info(&card->gdev->dev, | ||
3398 | "QDIO data connection isolation is activated\n"); | ||
3399 | } | ||
3400 | QETH_DBF_MESSAGE(3, "OK:SET_ACCESS_CTRL(%s, %d)==%d\n", | ||
3401 | card->gdev->dev.kobj.name, | ||
3402 | access_ctrl_req->subcmd_code, | ||
3403 | cmd->data.setadapterparms.hdr.return_code); | ||
3404 | rc = 0; | ||
3405 | break; | ||
3406 | } | ||
3407 | case SET_ACCESS_CTRL_RC_NOT_SUPPORTED: | ||
3408 | { | ||
3409 | QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n", | ||
3410 | card->gdev->dev.kobj.name, | ||
3411 | access_ctrl_req->subcmd_code, | ||
3412 | cmd->data.setadapterparms.hdr.return_code); | ||
3413 | dev_err(&card->gdev->dev, "Adapter does not " | ||
3414 | "support QDIO data connection isolation\n"); | ||
3415 | |||
3416 | /* ensure isolation mode is "none" */ | ||
3417 | card->options.isolation = ISOLATION_MODE_NONE; | ||
3418 | rc = -EOPNOTSUPP; | ||
3419 | break; | ||
3420 | } | ||
3421 | case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER: | ||
3422 | { | ||
3423 | QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n", | ||
3424 | card->gdev->dev.kobj.name, | ||
3425 | access_ctrl_req->subcmd_code, | ||
3426 | cmd->data.setadapterparms.hdr.return_code); | ||
3427 | dev_err(&card->gdev->dev, | ||
3428 | "Adapter is dedicated. " | ||
3429 | "QDIO data connection isolation not supported\n"); | ||
3430 | |||
3431 | /* ensure isolation mode is "none" */ | ||
3432 | card->options.isolation = ISOLATION_MODE_NONE; | ||
3433 | rc = -EOPNOTSUPP; | ||
3434 | break; | ||
3435 | } | ||
3436 | case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF: | ||
3437 | { | ||
3438 | QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n", | ||
3439 | card->gdev->dev.kobj.name, | ||
3440 | access_ctrl_req->subcmd_code, | ||
3441 | cmd->data.setadapterparms.hdr.return_code); | ||
3442 | dev_err(&card->gdev->dev, | ||
3443 | "TSO does not permit QDIO data connection isolation\n"); | ||
3444 | |||
3445 | /* ensure isolation mode is "none" */ | ||
3446 | card->options.isolation = ISOLATION_MODE_NONE; | ||
3447 | rc = -EPERM; | ||
3448 | break; | ||
3449 | } | ||
3450 | default: | ||
3451 | { | ||
3452 | /* this should never happen */ | ||
3453 | QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d" | ||
3454 | "==UNKNOWN\n", | ||
3455 | card->gdev->dev.kobj.name, | ||
3456 | access_ctrl_req->subcmd_code, | ||
3457 | cmd->data.setadapterparms.hdr.return_code); | ||
3458 | |||
3459 | /* ensure isolation mode is "none" */ | ||
3460 | card->options.isolation = ISOLATION_MODE_NONE; | ||
3461 | rc = 0; | ||
3462 | break; | ||
3463 | } | ||
3464 | } | ||
3465 | qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd); | ||
3466 | return rc; | ||
3467 | } | ||
3468 | |||
3469 | static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, | ||
3470 | enum qeth_ipa_isolation_modes isolation) | ||
3471 | { | ||
3472 | int rc; | ||
3473 | struct qeth_cmd_buffer *iob; | ||
3474 | struct qeth_ipa_cmd *cmd; | ||
3475 | struct qeth_set_access_ctrl *access_ctrl_req; | ||
3476 | |||
3477 | QETH_DBF_TEXT(TRACE, 4, "setacctl"); | ||
3478 | |||
3479 | QETH_DBF_TEXT_(SETUP, 2, "setacctl"); | ||
3480 | QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name); | ||
3481 | |||
3482 | iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_ACCESS_CONTROL, | ||
3483 | sizeof(struct qeth_ipacmd_setadpparms_hdr) + | ||
3484 | sizeof(struct qeth_set_access_ctrl)); | ||
3485 | cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); | ||
3486 | access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; | ||
3487 | access_ctrl_req->subcmd_code = isolation; | ||
3488 | |||
3489 | rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb, | ||
3490 | NULL); | ||
3491 | QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc); | ||
3492 | return rc; | ||
3493 | } | ||
3494 | |||
3495 | int qeth_set_access_ctrl_online(struct qeth_card *card) | ||
3496 | { | ||
3497 | int rc = 0; | ||
3498 | |||
3499 | QETH_DBF_TEXT(TRACE, 4, "setactlo"); | ||
3500 | |||
3501 | if (card->info.type == QETH_CARD_TYPE_OSAE && | ||
3502 | qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) { | ||
3503 | rc = qeth_setadpparms_set_access_ctrl(card, | ||
3504 | card->options.isolation); | ||
3505 | if (rc) { | ||
3506 | QETH_DBF_MESSAGE(3, | ||
3507 | "IPA(SET_ACCESS_CTRL,%s,%d) sent failed", | ||
3508 | card->gdev->dev.kobj.name, | ||
3509 | rc); | ||
3510 | } | ||
3511 | } else if (card->options.isolation != ISOLATION_MODE_NONE) { | ||
3512 | card->options.isolation = ISOLATION_MODE_NONE; | ||
3513 | |||
3514 | dev_err(&card->gdev->dev, "Adapter does not " | ||
3515 | "support QDIO data connection isolation\n"); | ||
3516 | rc = -EOPNOTSUPP; | ||
3517 | } | ||
3518 | return rc; | ||
3519 | } | ||
3520 | EXPORT_SYMBOL_GPL(qeth_set_access_ctrl_online); | ||
3521 | |||
3392 | void qeth_tx_timeout(struct net_device *dev) | 3522 | void qeth_tx_timeout(struct net_device *dev) |
3393 | { | 3523 | { |
3394 | struct qeth_card *card; | 3524 | struct qeth_card *card; |
3395 | 3525 | ||
3526 | QETH_DBF_TEXT(TRACE, 4, "txtimeo"); | ||
3396 | card = dev->ml_priv; | 3527 | card = dev->ml_priv; |
3397 | card->stats.tx_errors++; | 3528 | card->stats.tx_errors++; |
3398 | qeth_schedule_recovery(card); | 3529 | qeth_schedule_recovery(card); |
@@ -3674,9 +3805,6 @@ static int qeth_qdio_establish(struct qeth_card *card) | |||
3674 | init_data.input_handler = card->discipline.input_handler; | 3805 | init_data.input_handler = card->discipline.input_handler; |
3675 | init_data.output_handler = card->discipline.output_handler; | 3806 | init_data.output_handler = card->discipline.output_handler; |
3676 | init_data.int_parm = (unsigned long) card; | 3807 | init_data.int_parm = (unsigned long) card; |
3677 | init_data.flags = QDIO_INBOUND_0COPY_SBALS | | ||
3678 | QDIO_OUTBOUND_0COPY_SBALS | | ||
3679 | QDIO_USE_OUTBOUND_PCIS; | ||
3680 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; | 3808 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; |
3681 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; | 3809 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; |
3682 | 3810 | ||
@@ -3731,60 +3859,39 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, | |||
3731 | 3859 | ||
3732 | int qeth_core_hardsetup_card(struct qeth_card *card) | 3860 | int qeth_core_hardsetup_card(struct qeth_card *card) |
3733 | { | 3861 | { |
3734 | struct qdio_ssqd_desc *ssqd; | 3862 | int retries = 0; |
3735 | int retries = 3; | ||
3736 | int mpno = 0; | ||
3737 | int rc; | 3863 | int rc; |
3738 | 3864 | ||
3739 | QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); | 3865 | QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); |
3740 | atomic_set(&card->force_alloc_skb, 0); | 3866 | atomic_set(&card->force_alloc_skb, 0); |
3741 | retry: | 3867 | retry: |
3742 | if (retries < 3) { | 3868 | if (retries) |
3743 | QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n", | 3869 | QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n", |
3744 | dev_name(&card->gdev->dev)); | 3870 | dev_name(&card->gdev->dev)); |
3745 | ccw_device_set_offline(CARD_DDEV(card)); | 3871 | ccw_device_set_offline(CARD_DDEV(card)); |
3746 | ccw_device_set_offline(CARD_WDEV(card)); | 3872 | ccw_device_set_offline(CARD_WDEV(card)); |
3747 | ccw_device_set_offline(CARD_RDEV(card)); | 3873 | ccw_device_set_offline(CARD_RDEV(card)); |
3748 | ccw_device_set_online(CARD_RDEV(card)); | 3874 | rc = ccw_device_set_online(CARD_RDEV(card)); |
3749 | ccw_device_set_online(CARD_WDEV(card)); | 3875 | if (rc) |
3750 | ccw_device_set_online(CARD_DDEV(card)); | 3876 | goto retriable; |
3751 | } | 3877 | rc = ccw_device_set_online(CARD_WDEV(card)); |
3878 | if (rc) | ||
3879 | goto retriable; | ||
3880 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
3881 | if (rc) | ||
3882 | goto retriable; | ||
3752 | rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD); | 3883 | rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD); |
3884 | retriable: | ||
3753 | if (rc == -ERESTARTSYS) { | 3885 | if (rc == -ERESTARTSYS) { |
3754 | QETH_DBF_TEXT(SETUP, 2, "break1"); | 3886 | QETH_DBF_TEXT(SETUP, 2, "break1"); |
3755 | return rc; | 3887 | return rc; |
3756 | } else if (rc) { | 3888 | } else if (rc) { |
3757 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | 3889 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); |
3758 | if (--retries < 0) | 3890 | if (++retries > 3) |
3759 | goto out; | 3891 | goto out; |
3760 | else | 3892 | else |
3761 | goto retry; | 3893 | goto retry; |
3762 | } | 3894 | } |
3763 | |||
3764 | rc = qeth_get_unitaddr(card); | ||
3765 | if (rc) { | ||
3766 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | ||
3767 | return rc; | ||
3768 | } | ||
3769 | |||
3770 | ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); | ||
3771 | if (!ssqd) { | ||
3772 | rc = -ENOMEM; | ||
3773 | goto out; | ||
3774 | } | ||
3775 | rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); | ||
3776 | if (rc == 0) | ||
3777 | mpno = ssqd->pcnt; | ||
3778 | kfree(ssqd); | ||
3779 | |||
3780 | if (mpno) | ||
3781 | mpno = min(mpno - 1, QETH_MAX_PORTNO); | ||
3782 | if (card->info.portno > mpno) { | ||
3783 | QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d" | ||
3784 | "\n.", CARD_BUS_ID(card), card->info.portno); | ||
3785 | rc = -ENODEV; | ||
3786 | goto out; | ||
3787 | } | ||
3788 | qeth_init_tokens(card); | 3895 | qeth_init_tokens(card); |
3789 | qeth_init_func_level(card); | 3896 | qeth_init_func_level(card); |
3790 | rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); | 3897 | rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); |
@@ -3868,7 +3975,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, | |||
3868 | struct qdio_buffer_element *element = *__element; | 3975 | struct qdio_buffer_element *element = *__element; |
3869 | int offset = *__offset; | 3976 | int offset = *__offset; |
3870 | struct sk_buff *skb = NULL; | 3977 | struct sk_buff *skb = NULL; |
3871 | int skb_len; | 3978 | int skb_len = 0; |
3872 | void *data_ptr; | 3979 | void *data_ptr; |
3873 | int data_len; | 3980 | int data_len; |
3874 | int headroom = 0; | 3981 | int headroom = 0; |
@@ -3887,20 +3994,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, | |||
3887 | *hdr = element->addr + offset; | 3994 | *hdr = element->addr + offset; |
3888 | 3995 | ||
3889 | offset += sizeof(struct qeth_hdr); | 3996 | offset += sizeof(struct qeth_hdr); |
3890 | if (card->options.layer2) { | 3997 | switch ((*hdr)->hdr.l2.id) { |
3891 | if (card->info.type == QETH_CARD_TYPE_OSN) { | 3998 | case QETH_HEADER_TYPE_LAYER2: |
3892 | skb_len = (*hdr)->hdr.osn.pdu_length; | 3999 | skb_len = (*hdr)->hdr.l2.pkt_length; |
3893 | headroom = sizeof(struct qeth_hdr); | 4000 | break; |
3894 | } else { | 4001 | case QETH_HEADER_TYPE_LAYER3: |
3895 | skb_len = (*hdr)->hdr.l2.pkt_length; | ||
3896 | } | ||
3897 | } else { | ||
3898 | skb_len = (*hdr)->hdr.l3.length; | 4002 | skb_len = (*hdr)->hdr.l3.length; |
3899 | if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || | 4003 | if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || |
3900 | (card->info.link_type == QETH_LINK_TYPE_HSTR)) | 4004 | (card->info.link_type == QETH_LINK_TYPE_HSTR)) |
3901 | headroom = TR_HLEN; | 4005 | headroom = TR_HLEN; |
3902 | else | 4006 | else |
3903 | headroom = ETH_HLEN; | 4007 | headroom = ETH_HLEN; |
4008 | break; | ||
4009 | case QETH_HEADER_TYPE_OSN: | ||
4010 | skb_len = (*hdr)->hdr.osn.pdu_length; | ||
4011 | headroom = sizeof(struct qeth_hdr); | ||
4012 | break; | ||
4013 | default: | ||
4014 | break; | ||
3904 | } | 4015 | } |
3905 | 4016 | ||
3906 | if (!skb_len) | 4017 | if (!skb_len) |
@@ -4055,6 +4166,41 @@ void qeth_core_free_discipline(struct qeth_card *card) | |||
4055 | card->discipline.ccwgdriver = NULL; | 4166 | card->discipline.ccwgdriver = NULL; |
4056 | } | 4167 | } |
4057 | 4168 | ||
4169 | static void qeth_determine_capabilities(struct qeth_card *card) | ||
4170 | { | ||
4171 | int rc; | ||
4172 | int length; | ||
4173 | char *prcd; | ||
4174 | |||
4175 | QETH_DBF_TEXT(SETUP, 2, "detcapab"); | ||
4176 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
4177 | if (rc) { | ||
4178 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); | ||
4179 | goto out; | ||
4180 | } | ||
4181 | |||
4182 | |||
4183 | rc = qeth_read_conf_data(card, (void **) &prcd, &length); | ||
4184 | if (rc) { | ||
4185 | QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", | ||
4186 | dev_name(&card->gdev->dev), rc); | ||
4187 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | ||
4188 | goto out_offline; | ||
4189 | } | ||
4190 | qeth_configure_unitaddr(card, prcd); | ||
4191 | qeth_configure_blkt_default(card, prcd); | ||
4192 | kfree(prcd); | ||
4193 | |||
4194 | rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); | ||
4195 | if (rc) | ||
4196 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); | ||
4197 | |||
4198 | out_offline: | ||
4199 | ccw_device_set_offline(CARD_DDEV(card)); | ||
4200 | out: | ||
4201 | return; | ||
4202 | } | ||
4203 | |||
4058 | static int qeth_core_probe_device(struct ccwgroup_device *gdev) | 4204 | static int qeth_core_probe_device(struct ccwgroup_device *gdev) |
4059 | { | 4205 | { |
4060 | struct qeth_card *card; | 4206 | struct qeth_card *card; |
@@ -4120,6 +4266,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) | |||
4120 | write_lock_irqsave(&qeth_core_card_list.rwlock, flags); | 4266 | write_lock_irqsave(&qeth_core_card_list.rwlock, flags); |
4121 | list_add_tail(&card->list, &qeth_core_card_list.list); | 4267 | list_add_tail(&card->list, &qeth_core_card_list.list); |
4122 | write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); | 4268 | write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); |
4269 | |||
4270 | qeth_determine_capabilities(card); | ||
4123 | return 0; | 4271 | return 0; |
4124 | 4272 | ||
4125 | err_card: | 4273 | err_card: |
@@ -4303,13 +4451,19 @@ static struct { | |||
4303 | {"tx do_QDIO time"}, | 4451 | {"tx do_QDIO time"}, |
4304 | {"tx do_QDIO count"}, | 4452 | {"tx do_QDIO count"}, |
4305 | {"tx csum"}, | 4453 | {"tx csum"}, |
4454 | {"tx lin"}, | ||
4306 | }; | 4455 | }; |
4307 | 4456 | ||
4308 | int qeth_core_get_stats_count(struct net_device *dev) | 4457 | int qeth_core_get_sset_count(struct net_device *dev, int stringset) |
4309 | { | 4458 | { |
4310 | return (sizeof(qeth_ethtool_stats_keys) / ETH_GSTRING_LEN); | 4459 | switch (stringset) { |
4460 | case ETH_SS_STATS: | ||
4461 | return (sizeof(qeth_ethtool_stats_keys) / ETH_GSTRING_LEN); | ||
4462 | default: | ||
4463 | return -EINVAL; | ||
4464 | } | ||
4311 | } | 4465 | } |
4312 | EXPORT_SYMBOL_GPL(qeth_core_get_stats_count); | 4466 | EXPORT_SYMBOL_GPL(qeth_core_get_sset_count); |
4313 | 4467 | ||
4314 | void qeth_core_get_ethtool_stats(struct net_device *dev, | 4468 | void qeth_core_get_ethtool_stats(struct net_device *dev, |
4315 | struct ethtool_stats *stats, u64 *data) | 4469 | struct ethtool_stats *stats, u64 *data) |
@@ -4355,6 +4509,7 @@ void qeth_core_get_ethtool_stats(struct net_device *dev, | |||
4355 | data[31] = card->perf_stats.outbound_do_qdio_time; | 4509 | data[31] = card->perf_stats.outbound_do_qdio_time; |
4356 | data[32] = card->perf_stats.outbound_do_qdio_cnt; | 4510 | data[32] = card->perf_stats.outbound_do_qdio_cnt; |
4357 | data[33] = card->perf_stats.tx_csum; | 4511 | data[33] = card->perf_stats.tx_csum; |
4512 | data[34] = card->perf_stats.tx_lin; | ||
4358 | } | 4513 | } |
4359 | EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats); | 4514 | EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats); |
4360 | 4515 | ||
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index eecb2ee62e85..104a3351e02b 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h | |||
@@ -156,6 +156,8 @@ enum qeth_ipa_return_codes { | |||
156 | IPA_RC_IP_TABLE_FULL = 0x0002, | 156 | IPA_RC_IP_TABLE_FULL = 0x0002, |
157 | IPA_RC_UNKNOWN_ERROR = 0x0003, | 157 | IPA_RC_UNKNOWN_ERROR = 0x0003, |
158 | IPA_RC_UNSUPPORTED_COMMAND = 0x0004, | 158 | IPA_RC_UNSUPPORTED_COMMAND = 0x0004, |
159 | IPA_RC_TRACE_ALREADY_ACTIVE = 0x0005, | ||
160 | IPA_RC_INVALID_FORMAT = 0x0006, | ||
159 | IPA_RC_DUP_IPV6_REMOTE = 0x0008, | 161 | IPA_RC_DUP_IPV6_REMOTE = 0x0008, |
160 | IPA_RC_DUP_IPV6_HOME = 0x0010, | 162 | IPA_RC_DUP_IPV6_HOME = 0x0010, |
161 | IPA_RC_UNREGISTERED_ADDR = 0x0011, | 163 | IPA_RC_UNREGISTERED_ADDR = 0x0011, |
@@ -196,6 +198,11 @@ enum qeth_ipa_return_codes { | |||
196 | IPA_RC_INVALID_IP_VERSION2 = 0xf001, | 198 | IPA_RC_INVALID_IP_VERSION2 = 0xf001, |
197 | IPA_RC_FFFF = 0xffff | 199 | IPA_RC_FFFF = 0xffff |
198 | }; | 200 | }; |
201 | /* for DELIP */ | ||
202 | #define IPA_RC_IP_ADDRESS_NOT_DEFINED IPA_RC_PRIMARY_ALREADY_DEFINED | ||
203 | /* for SET_DIAGNOSTIC_ASSIST */ | ||
204 | #define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL | ||
205 | #define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR | ||
199 | 206 | ||
200 | /* IPA function flags; each flag marks availability of respective function */ | 207 | /* IPA function flags; each flag marks availability of respective function */ |
201 | enum qeth_ipa_funcs { | 208 | enum qeth_ipa_funcs { |
@@ -234,18 +241,20 @@ enum qeth_ipa_setdelip_flags { | |||
234 | 241 | ||
235 | /* SETADAPTER IPA Command: ****************************************************/ | 242 | /* SETADAPTER IPA Command: ****************************************************/ |
236 | enum qeth_ipa_setadp_cmd { | 243 | enum qeth_ipa_setadp_cmd { |
237 | IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x0001, | 244 | IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x00000001L, |
238 | IPA_SETADP_ALTER_MAC_ADDRESS = 0x0002, | 245 | IPA_SETADP_ALTER_MAC_ADDRESS = 0x00000002L, |
239 | IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x0004, | 246 | IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x00000004L, |
240 | IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x0008, | 247 | IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x00000008L, |
241 | IPA_SETADP_SET_ADDRESSING_MODE = 0x0010, | 248 | IPA_SETADP_SET_ADDRESSING_MODE = 0x00000010L, |
242 | IPA_SETADP_SET_CONFIG_PARMS = 0x0020, | 249 | IPA_SETADP_SET_CONFIG_PARMS = 0x00000020L, |
243 | IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x0040, | 250 | IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x00000040L, |
244 | IPA_SETADP_SET_BROADCAST_MODE = 0x0080, | 251 | IPA_SETADP_SET_BROADCAST_MODE = 0x00000080L, |
245 | IPA_SETADP_SEND_OSA_MESSAGE = 0x0100, | 252 | IPA_SETADP_SEND_OSA_MESSAGE = 0x00000100L, |
246 | IPA_SETADP_SET_SNMP_CONTROL = 0x0200, | 253 | IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L, |
247 | IPA_SETADP_QUERY_CARD_INFO = 0x0400, | 254 | IPA_SETADP_QUERY_CARD_INFO = 0x00000400L, |
248 | IPA_SETADP_SET_PROMISC_MODE = 0x0800, | 255 | IPA_SETADP_SET_PROMISC_MODE = 0x00000800L, |
256 | IPA_SETADP_SET_DIAG_ASSIST = 0x00002000L, | ||
257 | IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L, | ||
249 | }; | 258 | }; |
250 | enum qeth_ipa_mac_ops { | 259 | enum qeth_ipa_mac_ops { |
251 | CHANGE_ADDR_READ_MAC = 0, | 260 | CHANGE_ADDR_READ_MAC = 0, |
@@ -264,6 +273,20 @@ enum qeth_ipa_promisc_modes { | |||
264 | SET_PROMISC_MODE_OFF = 0, | 273 | SET_PROMISC_MODE_OFF = 0, |
265 | SET_PROMISC_MODE_ON = 1, | 274 | SET_PROMISC_MODE_ON = 1, |
266 | }; | 275 | }; |
276 | enum qeth_ipa_isolation_modes { | ||
277 | ISOLATION_MODE_NONE = 0x00000000L, | ||
278 | ISOLATION_MODE_FWD = 0x00000001L, | ||
279 | ISOLATION_MODE_DROP = 0x00000002L, | ||
280 | }; | ||
281 | enum qeth_ipa_set_access_mode_rc { | ||
282 | SET_ACCESS_CTRL_RC_SUCCESS = 0x0000, | ||
283 | SET_ACCESS_CTRL_RC_NOT_SUPPORTED = 0x0004, | ||
284 | SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED = 0x0008, | ||
285 | SET_ACCESS_CTRL_RC_ALREADY_ISOLATED = 0x0010, | ||
286 | SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER = 0x0014, | ||
287 | SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF = 0x0018, | ||
288 | }; | ||
289 | |||
267 | 290 | ||
268 | /* (SET)DELIP(M) IPA stuff ***************************************************/ | 291 | /* (SET)DELIP(M) IPA stuff ***************************************************/ |
269 | struct qeth_ipacmd_setdelip4 { | 292 | struct qeth_ipacmd_setdelip4 { |
@@ -376,6 +399,11 @@ struct qeth_snmp_ureq { | |||
376 | struct qeth_snmp_cmd cmd; | 399 | struct qeth_snmp_cmd cmd; |
377 | } __attribute__((packed)); | 400 | } __attribute__((packed)); |
378 | 401 | ||
402 | /* SET_ACCESS_CONTROL: same format for request and reply */ | ||
403 | struct qeth_set_access_ctrl { | ||
404 | __u32 subcmd_code; | ||
405 | } __attribute__((packed)); | ||
406 | |||
379 | struct qeth_ipacmd_setadpparms_hdr { | 407 | struct qeth_ipacmd_setadpparms_hdr { |
380 | __u32 supp_hw_cmds; | 408 | __u32 supp_hw_cmds; |
381 | __u32 reserved1; | 409 | __u32 reserved1; |
@@ -394,6 +422,7 @@ struct qeth_ipacmd_setadpparms { | |||
394 | struct qeth_query_cmds_supp query_cmds_supp; | 422 | struct qeth_query_cmds_supp query_cmds_supp; |
395 | struct qeth_change_addr change_addr; | 423 | struct qeth_change_addr change_addr; |
396 | struct qeth_snmp_cmd snmp; | 424 | struct qeth_snmp_cmd snmp; |
425 | struct qeth_set_access_ctrl set_access_ctrl; | ||
397 | __u32 mode; | 426 | __u32 mode; |
398 | } data; | 427 | } data; |
399 | } __attribute__ ((packed)); | 428 | } __attribute__ ((packed)); |
@@ -403,6 +432,40 @@ struct qeth_create_destroy_address { | |||
403 | __u8 unique_id[8]; | 432 | __u8 unique_id[8]; |
404 | } __attribute__ ((packed)); | 433 | } __attribute__ ((packed)); |
405 | 434 | ||
435 | /* SET DIAGNOSTIC ASSIST IPA Command: *************************************/ | ||
436 | |||
437 | enum qeth_diags_cmds { | ||
438 | QETH_DIAGS_CMD_QUERY = 0x0001, | ||
439 | QETH_DIAGS_CMD_TRAP = 0x0002, | ||
440 | QETH_DIAGS_CMD_TRACE = 0x0004, | ||
441 | QETH_DIAGS_CMD_NOLOG = 0x0008, | ||
442 | QETH_DIAGS_CMD_DUMP = 0x0010, | ||
443 | }; | ||
444 | |||
445 | enum qeth_diags_trace_types { | ||
446 | QETH_DIAGS_TYPE_HIPERSOCKET = 0x02, | ||
447 | }; | ||
448 | |||
449 | enum qeth_diags_trace_cmds { | ||
450 | QETH_DIAGS_CMD_TRACE_ENABLE = 0x0001, | ||
451 | QETH_DIAGS_CMD_TRACE_DISABLE = 0x0002, | ||
452 | QETH_DIAGS_CMD_TRACE_MODIFY = 0x0004, | ||
453 | QETH_DIAGS_CMD_TRACE_REPLACE = 0x0008, | ||
454 | QETH_DIAGS_CMD_TRACE_QUERY = 0x0010, | ||
455 | }; | ||
456 | |||
457 | struct qeth_ipacmd_diagass { | ||
458 | __u32 host_tod2; | ||
459 | __u32:32; | ||
460 | __u16 subcmd_len; | ||
461 | __u16:16; | ||
462 | __u32 subcmd; | ||
463 | __u8 type; | ||
464 | __u8 action; | ||
465 | __u16 options; | ||
466 | __u32:32; | ||
467 | } __attribute__ ((packed)); | ||
468 | |||
406 | /* Header for each IPA command */ | 469 | /* Header for each IPA command */ |
407 | struct qeth_ipacmd_hdr { | 470 | struct qeth_ipacmd_hdr { |
408 | __u8 command; | 471 | __u8 command; |
@@ -431,6 +494,7 @@ struct qeth_ipa_cmd { | |||
431 | struct qeth_create_destroy_address create_destroy_addr; | 494 | struct qeth_create_destroy_address create_destroy_addr; |
432 | struct qeth_ipacmd_setadpparms setadapterparms; | 495 | struct qeth_ipacmd_setadpparms setadapterparms; |
433 | struct qeth_set_routing setrtg; | 496 | struct qeth_set_routing setrtg; |
497 | struct qeth_ipacmd_diagass diagass; | ||
434 | } data; | 498 | } data; |
435 | } __attribute__ ((packed)); | 499 | } __attribute__ ((packed)); |
436 | 500 | ||
@@ -448,7 +512,6 @@ enum qeth_ipa_arp_return_codes { | |||
448 | QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, | 512 | QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, |
449 | }; | 513 | }; |
450 | 514 | ||
451 | |||
452 | extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); | 515 | extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); |
453 | extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); | 516 | extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); |
454 | 517 | ||
@@ -507,7 +570,7 @@ extern unsigned char ULP_ENABLE[]; | |||
507 | (PDU_ENCAPSULATION(buffer) + 0x17) | 570 | (PDU_ENCAPSULATION(buffer) + 0x17) |
508 | #define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) \ | 571 | #define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) \ |
509 | (PDU_ENCAPSULATION(buffer) + 0x2b) | 572 | (PDU_ENCAPSULATION(buffer) + 0x2b) |
510 | /* Layer 2 defintions */ | 573 | /* Layer 2 definitions */ |
511 | #define QETH_PROT_LAYER2 0x08 | 574 | #define QETH_PROT_LAYER2 0x08 |
512 | #define QETH_PROT_TCPIP 0x03 | 575 | #define QETH_PROT_TCPIP 0x03 |
513 | #define QETH_PROT_OSN2 0x0a | 576 | #define QETH_PROT_OSN2 0x0a |
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 33505c2a0e3a..25dfd5abd19b 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c | |||
@@ -8,6 +8,9 @@ | |||
8 | * Frank Blaschka <frank.blaschka@de.ibm.com> | 8 | * Frank Blaschka <frank.blaschka@de.ibm.com> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #define KMSG_COMPONENT "qeth" | ||
12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
13 | |||
11 | #include <linux/list.h> | 14 | #include <linux/list.h> |
12 | #include <linux/rwsem.h> | 15 | #include <linux/rwsem.h> |
13 | #include <asm/ebcdic.h> | 16 | #include <asm/ebcdic.h> |
@@ -118,7 +121,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev, | |||
118 | { | 121 | { |
119 | struct qeth_card *card = dev_get_drvdata(dev); | 122 | struct qeth_card *card = dev_get_drvdata(dev); |
120 | char *tmp; | 123 | char *tmp; |
121 | unsigned int portno; | 124 | unsigned int portno, limit; |
122 | 125 | ||
123 | if (!card) | 126 | if (!card) |
124 | return -EINVAL; | 127 | return -EINVAL; |
@@ -128,9 +131,11 @@ static ssize_t qeth_dev_portno_store(struct device *dev, | |||
128 | return -EPERM; | 131 | return -EPERM; |
129 | 132 | ||
130 | portno = simple_strtoul(buf, &tmp, 16); | 133 | portno = simple_strtoul(buf, &tmp, 16); |
131 | if (portno > QETH_MAX_PORTNO) { | 134 | if (portno > QETH_MAX_PORTNO) |
135 | return -EINVAL; | ||
136 | limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt); | ||
137 | if (portno > limit) | ||
132 | return -EINVAL; | 138 | return -EINVAL; |
133 | } | ||
134 | 139 | ||
135 | card->info.portno = portno; | 140 | card->info.portno = portno; |
136 | return count; | 141 | return count; |
@@ -416,7 +421,11 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, | |||
416 | static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show, | 421 | static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show, |
417 | qeth_dev_layer2_store); | 422 | qeth_dev_layer2_store); |
418 | 423 | ||
419 | static ssize_t qeth_dev_large_send_show(struct device *dev, | 424 | #define ATTR_QETH_ISOLATION_NONE ("none") |
425 | #define ATTR_QETH_ISOLATION_FWD ("forward") | ||
426 | #define ATTR_QETH_ISOLATION_DROP ("drop") | ||
427 | |||
428 | static ssize_t qeth_dev_isolation_show(struct device *dev, | ||
420 | struct device_attribute *attr, char *buf) | 429 | struct device_attribute *attr, char *buf) |
421 | { | 430 | { |
422 | struct qeth_card *card = dev_get_drvdata(dev); | 431 | struct qeth_card *card = dev_get_drvdata(dev); |
@@ -424,44 +433,69 @@ static ssize_t qeth_dev_large_send_show(struct device *dev, | |||
424 | if (!card) | 433 | if (!card) |
425 | return -EINVAL; | 434 | return -EINVAL; |
426 | 435 | ||
427 | switch (card->options.large_send) { | 436 | switch (card->options.isolation) { |
428 | case QETH_LARGE_SEND_NO: | 437 | case ISOLATION_MODE_NONE: |
429 | return sprintf(buf, "%s\n", "no"); | 438 | return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_NONE); |
430 | case QETH_LARGE_SEND_TSO: | 439 | case ISOLATION_MODE_FWD: |
431 | return sprintf(buf, "%s\n", "TSO"); | 440 | return snprintf(buf, 9, "%s\n", ATTR_QETH_ISOLATION_FWD); |
441 | case ISOLATION_MODE_DROP: | ||
442 | return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_DROP); | ||
432 | default: | 443 | default: |
433 | return sprintf(buf, "%s\n", "N/A"); | 444 | return snprintf(buf, 5, "%s\n", "N/A"); |
434 | } | 445 | } |
435 | } | 446 | } |
436 | 447 | ||
437 | static ssize_t qeth_dev_large_send_store(struct device *dev, | 448 | static ssize_t qeth_dev_isolation_store(struct device *dev, |
438 | struct device_attribute *attr, const char *buf, size_t count) | 449 | struct device_attribute *attr, const char *buf, size_t count) |
439 | { | 450 | { |
440 | struct qeth_card *card = dev_get_drvdata(dev); | 451 | struct qeth_card *card = dev_get_drvdata(dev); |
441 | enum qeth_large_send_types type; | 452 | enum qeth_ipa_isolation_modes isolation; |
442 | int rc = 0; | 453 | int rc = 0; |
443 | char *tmp; | 454 | char *tmp, *curtoken; |
455 | curtoken = (char *) buf; | ||
444 | 456 | ||
445 | if (!card) | 457 | if (!card) { |
446 | return -EINVAL; | 458 | rc = -EINVAL; |
447 | tmp = strsep((char **) &buf, "\n"); | 459 | goto out; |
448 | if (!strcmp(tmp, "no")) { | 460 | } |
449 | type = QETH_LARGE_SEND_NO; | 461 | |
450 | } else if (!strcmp(tmp, "TSO")) { | 462 | /* check for unknown, too, in case we do not yet know who we are */ |
451 | type = QETH_LARGE_SEND_TSO; | 463 | if (card->info.type != QETH_CARD_TYPE_OSAE && |
464 | card->info.type != QETH_CARD_TYPE_UNKNOWN) { | ||
465 | rc = -EOPNOTSUPP; | ||
466 | dev_err(&card->gdev->dev, "Adapter does not " | ||
467 | "support QDIO data connection isolation\n"); | ||
468 | goto out; | ||
469 | } | ||
470 | |||
471 | /* parse input into isolation mode */ | ||
472 | tmp = strsep(&curtoken, "\n"); | ||
473 | if (!strcmp(tmp, ATTR_QETH_ISOLATION_NONE)) { | ||
474 | isolation = ISOLATION_MODE_NONE; | ||
475 | } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_FWD)) { | ||
476 | isolation = ISOLATION_MODE_FWD; | ||
477 | } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_DROP)) { | ||
478 | isolation = ISOLATION_MODE_DROP; | ||
452 | } else { | 479 | } else { |
453 | return -EINVAL; | 480 | rc = -EINVAL; |
481 | goto out; | ||
454 | } | 482 | } |
455 | if (card->options.large_send == type) | 483 | rc = count; |
456 | return count; | 484 | |
457 | rc = qeth_set_large_send(card, type); | 485 | /* defer IP assist if device is offline (until discipline->set_online)*/ |
458 | if (rc) | 486 | card->options.isolation = isolation; |
459 | return rc; | 487 | if (card->state == CARD_STATE_SOFTSETUP || |
460 | return count; | 488 | card->state == CARD_STATE_UP) { |
489 | int ipa_rc = qeth_set_access_ctrl_online(card); | ||
490 | if (ipa_rc != 0) | ||
491 | rc = ipa_rc; | ||
492 | } | ||
493 | out: | ||
494 | return rc; | ||
461 | } | 495 | } |
462 | 496 | ||
463 | static DEVICE_ATTR(large_send, 0644, qeth_dev_large_send_show, | 497 | static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show, |
464 | qeth_dev_large_send_store); | 498 | qeth_dev_isolation_store); |
465 | 499 | ||
466 | static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value) | 500 | static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value) |
467 | { | 501 | { |
@@ -508,7 +542,7 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev, | |||
508 | struct qeth_card *card = dev_get_drvdata(dev); | 542 | struct qeth_card *card = dev_get_drvdata(dev); |
509 | 543 | ||
510 | return qeth_dev_blkt_store(card, buf, count, | 544 | return qeth_dev_blkt_store(card, buf, count, |
511 | &card->info.blkt.time_total, 1000); | 545 | &card->info.blkt.time_total, 5000); |
512 | } | 546 | } |
513 | 547 | ||
514 | 548 | ||
@@ -530,7 +564,7 @@ static ssize_t qeth_dev_blkt_inter_store(struct device *dev, | |||
530 | struct qeth_card *card = dev_get_drvdata(dev); | 564 | struct qeth_card *card = dev_get_drvdata(dev); |
531 | 565 | ||
532 | return qeth_dev_blkt_store(card, buf, count, | 566 | return qeth_dev_blkt_store(card, buf, count, |
533 | &card->info.blkt.inter_packet, 100); | 567 | &card->info.blkt.inter_packet, 1000); |
534 | } | 568 | } |
535 | 569 | ||
536 | static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show, | 570 | static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show, |
@@ -551,7 +585,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev, | |||
551 | struct qeth_card *card = dev_get_drvdata(dev); | 585 | struct qeth_card *card = dev_get_drvdata(dev); |
552 | 586 | ||
553 | return qeth_dev_blkt_store(card, buf, count, | 587 | return qeth_dev_blkt_store(card, buf, count, |
554 | &card->info.blkt.inter_packet_jumbo, 100); | 588 | &card->info.blkt.inter_packet_jumbo, 1000); |
555 | } | 589 | } |
556 | 590 | ||
557 | static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show, | 591 | static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show, |
@@ -582,7 +616,7 @@ static struct attribute *qeth_device_attrs[] = { | |||
582 | &dev_attr_recover.attr, | 616 | &dev_attr_recover.attr, |
583 | &dev_attr_performance_stats.attr, | 617 | &dev_attr_performance_stats.attr, |
584 | &dev_attr_layer2.attr, | 618 | &dev_attr_layer2.attr, |
585 | &dev_attr_large_send.attr, | 619 | &dev_attr_isolation.attr, |
586 | NULL, | 620 | NULL, |
587 | }; | 621 | }; |
588 | 622 | ||
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index f4f3ca1393b2..6a801dc3bf8e 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/slab.h> | ||
19 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
20 | #include <linux/mii.h> | 21 | #include <linux/mii.h> |
21 | #include <linux/ip.h> | 22 | #include <linux/ip.h> |
@@ -486,22 +487,14 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, | |||
486 | case IPA_RC_L2_DUP_MAC: | 487 | case IPA_RC_L2_DUP_MAC: |
487 | case IPA_RC_L2_DUP_LAYER3_MAC: | 488 | case IPA_RC_L2_DUP_LAYER3_MAC: |
488 | dev_warn(&card->gdev->dev, | 489 | dev_warn(&card->gdev->dev, |
489 | "MAC address " | 490 | "MAC address %pM already exists\n", |
490 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | 491 | card->dev->dev_addr); |
491 | "already exists\n", | ||
492 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
493 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
494 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
495 | break; | 492 | break; |
496 | case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: | 493 | case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: |
497 | case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: | 494 | case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: |
498 | dev_warn(&card->gdev->dev, | 495 | dev_warn(&card->gdev->dev, |
499 | "MAC address " | 496 | "MAC address %pM is not authorized\n", |
500 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | 497 | card->dev->dev_addr); |
501 | "is not authorized\n", | ||
502 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
503 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
504 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
505 | break; | 498 | break; |
506 | default: | 499 | default: |
507 | break; | 500 | break; |
@@ -512,12 +505,8 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, | |||
512 | memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, | 505 | memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, |
513 | OSA_ADDR_LEN); | 506 | OSA_ADDR_LEN); |
514 | dev_info(&card->gdev->dev, | 507 | dev_info(&card->gdev->dev, |
515 | "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | 508 | "MAC address %pM successfully registered on device %s\n", |
516 | "successfully registered on device %s\n", | 509 | card->dev->dev_addr, card->dev->name); |
517 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
518 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
519 | card->dev->dev_addr[4], card->dev->dev_addr[5], | ||
520 | card->dev->name); | ||
521 | } | 510 | } |
522 | return 0; | 511 | return 0; |
523 | } | 512 | } |
@@ -634,7 +623,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) | |||
634 | for (dm = dev->mc_list; dm; dm = dm->next) | 623 | for (dm = dev->mc_list; dm; dm = dm->next) |
635 | qeth_l2_add_mc(card, dm->da_addr, 0); | 624 | qeth_l2_add_mc(card, dm->da_addr, 0); |
636 | 625 | ||
637 | list_for_each_entry(ha, &dev->uc.list, list) | 626 | netdev_for_each_uc_addr(ha, dev) |
638 | qeth_l2_add_mc(card, ha->addr, 1); | 627 | qeth_l2_add_mc(card, ha->addr, 1); |
639 | 628 | ||
640 | spin_unlock_bh(&card->mclock); | 629 | spin_unlock_bh(&card->mclock); |
@@ -781,7 +770,8 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, | |||
781 | index = i % QDIO_MAX_BUFFERS_PER_Q; | 770 | index = i % QDIO_MAX_BUFFERS_PER_Q; |
782 | buffer = &card->qdio.in_q->bufs[index]; | 771 | buffer = &card->qdio.in_q->bufs[index]; |
783 | if (!(qdio_err && | 772 | if (!(qdio_err && |
784 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qinerr"))) | 773 | qeth_check_qdio_errors(card, buffer->buffer, qdio_err, |
774 | "qinerr"))) | ||
785 | qeth_l2_process_inbound_buffer(card, buffer, index); | 775 | qeth_l2_process_inbound_buffer(card, buffer, index); |
786 | /* clear buffer and give back to hardware */ | 776 | /* clear buffer and give back to hardware */ |
787 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); | 777 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); |
@@ -866,7 +856,7 @@ static const struct ethtool_ops qeth_l2_ethtool_ops = { | |||
866 | .get_link = ethtool_op_get_link, | 856 | .get_link = ethtool_op_get_link, |
867 | .get_strings = qeth_core_get_strings, | 857 | .get_strings = qeth_core_get_strings, |
868 | .get_ethtool_stats = qeth_core_get_ethtool_stats, | 858 | .get_ethtool_stats = qeth_core_get_ethtool_stats, |
869 | .get_stats_count = qeth_core_get_stats_count, | 859 | .get_sset_count = qeth_core_get_sset_count, |
870 | .get_drvinfo = qeth_core_get_drvinfo, | 860 | .get_drvinfo = qeth_core_get_drvinfo, |
871 | .get_settings = qeth_core_ethtool_get_settings, | 861 | .get_settings = qeth_core_ethtool_get_settings, |
872 | }; | 862 | }; |
@@ -874,7 +864,7 @@ static const struct ethtool_ops qeth_l2_ethtool_ops = { | |||
874 | static const struct ethtool_ops qeth_l2_osn_ops = { | 864 | static const struct ethtool_ops qeth_l2_osn_ops = { |
875 | .get_strings = qeth_core_get_strings, | 865 | .get_strings = qeth_core_get_strings, |
876 | .get_ethtool_stats = qeth_core_get_ethtool_stats, | 866 | .get_ethtool_stats = qeth_core_get_ethtool_stats, |
877 | .get_stats_count = qeth_core_get_stats_count, | 867 | .get_sset_count = qeth_core_get_sset_count, |
878 | .get_drvinfo = qeth_core_get_drvinfo, | 868 | .get_drvinfo = qeth_core_get_drvinfo, |
879 | }; | 869 | }; |
880 | 870 | ||
@@ -938,32 +928,18 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
938 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); | 928 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); |
939 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 929 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
940 | 930 | ||
941 | qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); | ||
942 | recover_flag = card->state; | 931 | recover_flag = card->state; |
943 | rc = ccw_device_set_online(CARD_RDEV(card)); | ||
944 | if (rc) { | ||
945 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
946 | return -EIO; | ||
947 | } | ||
948 | rc = ccw_device_set_online(CARD_WDEV(card)); | ||
949 | if (rc) { | ||
950 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
951 | return -EIO; | ||
952 | } | ||
953 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
954 | if (rc) { | ||
955 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
956 | return -EIO; | ||
957 | } | ||
958 | |||
959 | rc = qeth_core_hardsetup_card(card); | 932 | rc = qeth_core_hardsetup_card(card); |
960 | if (rc) { | 933 | if (rc) { |
961 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 934 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
935 | rc = -ENODEV; | ||
962 | goto out_remove; | 936 | goto out_remove; |
963 | } | 937 | } |
964 | 938 | ||
965 | if (!card->dev && qeth_l2_setup_netdev(card)) | 939 | if (!card->dev && qeth_l2_setup_netdev(card)) { |
940 | rc = -ENODEV; | ||
966 | goto out_remove; | 941 | goto out_remove; |
942 | } | ||
967 | 943 | ||
968 | if (card->info.type != QETH_CARD_TYPE_OSN) | 944 | if (card->info.type != QETH_CARD_TYPE_OSN) |
969 | qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); | 945 | qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); |
@@ -983,12 +959,14 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
983 | card->lan_online = 0; | 959 | card->lan_online = 0; |
984 | return 0; | 960 | return 0; |
985 | } | 961 | } |
962 | rc = -ENODEV; | ||
986 | goto out_remove; | 963 | goto out_remove; |
987 | } else | 964 | } else |
988 | card->lan_online = 1; | 965 | card->lan_online = 1; |
989 | 966 | ||
990 | if (card->info.type != QETH_CARD_TYPE_OSN) { | 967 | if (card->info.type != QETH_CARD_TYPE_OSN) { |
991 | qeth_set_large_send(card, card->options.large_send); | 968 | /* configure isolation level */ |
969 | qeth_set_access_ctrl_online(card); | ||
992 | qeth_l2_process_vlans(card, 0); | 970 | qeth_l2_process_vlans(card, 0); |
993 | } | 971 | } |
994 | 972 | ||
@@ -997,6 +975,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
997 | rc = qeth_init_qdio_queues(card); | 975 | rc = qeth_init_qdio_queues(card); |
998 | if (rc) { | 976 | if (rc) { |
999 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); | 977 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); |
978 | rc = -ENODEV; | ||
1000 | goto out_remove; | 979 | goto out_remove; |
1001 | } | 980 | } |
1002 | card->state = CARD_STATE_SOFTSETUP; | 981 | card->state = CARD_STATE_SOFTSETUP; |
@@ -1018,6 +997,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
1018 | /* let user_space know that device is online */ | 997 | /* let user_space know that device is online */ |
1019 | kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); | 998 | kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); |
1020 | return 0; | 999 | return 0; |
1000 | |||
1021 | out_remove: | 1001 | out_remove: |
1022 | card->use_hard_stop = 1; | 1002 | card->use_hard_stop = 1; |
1023 | qeth_l2_stop_card(card, 0); | 1003 | qeth_l2_stop_card(card, 0); |
@@ -1028,7 +1008,7 @@ out_remove: | |||
1028 | card->state = CARD_STATE_RECOVER; | 1008 | card->state = CARD_STATE_RECOVER; |
1029 | else | 1009 | else |
1030 | card->state = CARD_STATE_DOWN; | 1010 | card->state = CARD_STATE_DOWN; |
1031 | return -ENODEV; | 1011 | return rc; |
1032 | } | 1012 | } |
1033 | 1013 | ||
1034 | static int qeth_l2_set_online(struct ccwgroup_device *gdev) | 1014 | static int qeth_l2_set_online(struct ccwgroup_device *gdev) |
@@ -1092,11 +1072,9 @@ static int qeth_l2_recover(void *ptr) | |||
1092 | dev_info(&card->gdev->dev, | 1072 | dev_info(&card->gdev->dev, |
1093 | "Device successfully recovered!\n"); | 1073 | "Device successfully recovered!\n"); |
1094 | else { | 1074 | else { |
1095 | if (card->dev) { | 1075 | rtnl_lock(); |
1096 | rtnl_lock(); | 1076 | dev_close(card->dev); |
1097 | dev_close(card->dev); | 1077 | rtnl_unlock(); |
1098 | rtnl_unlock(); | ||
1099 | } | ||
1100 | dev_warn(&card->gdev->dev, "The qeth device driver " | 1078 | dev_warn(&card->gdev->dev, "The qeth device driver " |
1101 | "failed to recover an error on the device\n"); | 1079 | "failed to recover an error on the device\n"); |
1102 | } | 1080 | } |
@@ -1150,11 +1128,9 @@ static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) | |||
1150 | if (card->state == CARD_STATE_RECOVER) { | 1128 | if (card->state == CARD_STATE_RECOVER) { |
1151 | rc = __qeth_l2_set_online(card->gdev, 1); | 1129 | rc = __qeth_l2_set_online(card->gdev, 1); |
1152 | if (rc) { | 1130 | if (rc) { |
1153 | if (card->dev) { | 1131 | rtnl_lock(); |
1154 | rtnl_lock(); | 1132 | dev_close(card->dev); |
1155 | dev_close(card->dev); | 1133 | rtnl_unlock(); |
1156 | rtnl_unlock(); | ||
1157 | } | ||
1158 | } | 1134 | } |
1159 | } else | 1135 | } else |
1160 | rc = __qeth_l2_set_online(card->gdev, 0); | 1136 | rc = __qeth_l2_set_online(card->gdev, 0); |
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 9f143c83bba3..8447d233d0b3 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h | |||
@@ -13,6 +13,8 @@ | |||
13 | 13 | ||
14 | #include "qeth_core.h" | 14 | #include "qeth_core.h" |
15 | 15 | ||
16 | #define QETH_SNIFF_AVAIL 0x0008 | ||
17 | |||
16 | struct qeth_ipaddr { | 18 | struct qeth_ipaddr { |
17 | struct list_head entry; | 19 | struct list_head entry; |
18 | enum qeth_ip_types type; | 20 | enum qeth_ip_types type; |
@@ -60,5 +62,7 @@ void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); | |||
60 | int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); | 62 | int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); |
61 | void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions, | 63 | void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions, |
62 | const u8 *); | 64 | const u8 *); |
65 | int qeth_l3_set_large_send(struct qeth_card *, enum qeth_large_send_types); | ||
66 | int qeth_l3_set_rx_csum(struct qeth_card *, enum qeth_checksum_types); | ||
63 | 67 | ||
64 | #endif /* __QETH_L3_H__ */ | 68 | #endif /* __QETH_L3_H__ */ |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 073b6d354915..fc6ca1da8b98 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ipv6.h> | 22 | #include <linux/ipv6.h> |
23 | #include <linux/inetdevice.h> | 23 | #include <linux/inetdevice.h> |
24 | #include <linux/igmp.h> | 24 | #include <linux/igmp.h> |
25 | #include <linux/slab.h> | ||
25 | 26 | ||
26 | #include <net/ip.h> | 27 | #include <net/ip.h> |
27 | #include <net/arp.h> | 28 | #include <net/arp.h> |
@@ -41,6 +42,32 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *, | |||
41 | static int __qeth_l3_set_online(struct ccwgroup_device *, int); | 42 | static int __qeth_l3_set_online(struct ccwgroup_device *, int); |
42 | static int __qeth_l3_set_offline(struct ccwgroup_device *, int); | 43 | static int __qeth_l3_set_offline(struct ccwgroup_device *, int); |
43 | 44 | ||
45 | int qeth_l3_set_large_send(struct qeth_card *card, | ||
46 | enum qeth_large_send_types type) | ||
47 | { | ||
48 | int rc = 0; | ||
49 | |||
50 | card->options.large_send = type; | ||
51 | if (card->dev == NULL) | ||
52 | return 0; | ||
53 | |||
54 | if (card->options.large_send == QETH_LARGE_SEND_TSO) { | ||
55 | if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { | ||
56 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG | | ||
57 | NETIF_F_HW_CSUM; | ||
58 | } else { | ||
59 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
60 | NETIF_F_HW_CSUM); | ||
61 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
62 | rc = -EOPNOTSUPP; | ||
63 | } | ||
64 | } else { | ||
65 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
66 | NETIF_F_HW_CSUM); | ||
67 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
68 | } | ||
69 | return rc; | ||
70 | } | ||
44 | 71 | ||
45 | static int qeth_l3_isxdigit(char *buf) | 72 | static int qeth_l3_isxdigit(char *buf) |
46 | { | 73 | { |
@@ -216,6 +243,8 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card, | |||
216 | struct qeth_ipaddr *tmp, *t; | 243 | struct qeth_ipaddr *tmp, *t; |
217 | int found = 0; | 244 | int found = 0; |
218 | 245 | ||
246 | if (card->options.sniffer) | ||
247 | return 0; | ||
219 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { | 248 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { |
220 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && | 249 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && |
221 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) | 250 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) |
@@ -431,6 +460,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
431 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); | 460 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); |
432 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); | 461 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); |
433 | 462 | ||
463 | if (card->options.sniffer) | ||
464 | return; | ||
434 | spin_lock_irqsave(&card->ip_lock, flags); | 465 | spin_lock_irqsave(&card->ip_lock, flags); |
435 | tbd_list = card->ip_tbd_list; | 466 | tbd_list = card->ip_tbd_list; |
436 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); | 467 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); |
@@ -469,7 +500,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
469 | spin_unlock_irqrestore(&card->ip_lock, flags); | 500 | spin_unlock_irqrestore(&card->ip_lock, flags); |
470 | rc = qeth_l3_deregister_addr_entry(card, addr); | 501 | rc = qeth_l3_deregister_addr_entry(card, addr); |
471 | spin_lock_irqsave(&card->ip_lock, flags); | 502 | spin_lock_irqsave(&card->ip_lock, flags); |
472 | if (!rc || (rc == IPA_RC_PRIMARY_ALREADY_DEFINED)) | 503 | if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED)) |
473 | kfree(addr); | 504 | kfree(addr); |
474 | else | 505 | else |
475 | list_add_tail(&addr->entry, &card->ip_list); | 506 | list_add_tail(&addr->entry, &card->ip_list); |
@@ -487,6 +518,8 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean, | |||
487 | unsigned long flags; | 518 | unsigned long flags; |
488 | 519 | ||
489 | QETH_DBF_TEXT(TRACE, 4, "clearip"); | 520 | QETH_DBF_TEXT(TRACE, 4, "clearip"); |
521 | if (recover && card->options.sniffer) | ||
522 | return; | ||
490 | spin_lock_irqsave(&card->ip_lock, flags); | 523 | spin_lock_irqsave(&card->ip_lock, flags); |
491 | /* clear todo list */ | 524 | /* clear todo list */ |
492 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { | 525 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { |
@@ -1439,6 +1472,35 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) | |||
1439 | return 0; | 1472 | return 0; |
1440 | } | 1473 | } |
1441 | 1474 | ||
1475 | int qeth_l3_set_rx_csum(struct qeth_card *card, | ||
1476 | enum qeth_checksum_types csum_type) | ||
1477 | { | ||
1478 | int rc = 0; | ||
1479 | |||
1480 | if (card->options.checksum_type == HW_CHECKSUMMING) { | ||
1481 | if ((csum_type != HW_CHECKSUMMING) && | ||
1482 | (card->state != CARD_STATE_DOWN)) { | ||
1483 | rc = qeth_l3_send_simple_setassparms(card, | ||
1484 | IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); | ||
1485 | if (rc) | ||
1486 | return -EIO; | ||
1487 | } | ||
1488 | } else { | ||
1489 | if (csum_type == HW_CHECKSUMMING) { | ||
1490 | if (card->state != CARD_STATE_DOWN) { | ||
1491 | if (!qeth_is_supported(card, | ||
1492 | IPA_INBOUND_CHECKSUM)) | ||
1493 | return -EPERM; | ||
1494 | rc = qeth_l3_send_checksum_command(card); | ||
1495 | if (rc) | ||
1496 | return -EIO; | ||
1497 | } | ||
1498 | } | ||
1499 | } | ||
1500 | card->options.checksum_type = csum_type; | ||
1501 | return rc; | ||
1502 | } | ||
1503 | |||
1442 | static int qeth_l3_start_ipa_checksum(struct qeth_card *card) | 1504 | static int qeth_l3_start_ipa_checksum(struct qeth_card *card) |
1443 | { | 1505 | { |
1444 | int rc = 0; | 1506 | int rc = 0; |
@@ -1506,6 +1568,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card) | |||
1506 | static int qeth_l3_start_ipassists(struct qeth_card *card) | 1568 | static int qeth_l3_start_ipassists(struct qeth_card *card) |
1507 | { | 1569 | { |
1508 | QETH_DBF_TEXT(TRACE, 3, "strtipas"); | 1570 | QETH_DBF_TEXT(TRACE, 3, "strtipas"); |
1571 | |||
1572 | qeth_set_access_ctrl_online(card); /* go on*/ | ||
1509 | qeth_l3_start_ipa_arp_processing(card); /* go on*/ | 1573 | qeth_l3_start_ipa_arp_processing(card); /* go on*/ |
1510 | qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ | 1574 | qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ |
1511 | qeth_l3_start_ipa_source_mac(card); /* go on*/ | 1575 | qeth_l3_start_ipa_source_mac(card); /* go on*/ |
@@ -1617,6 +1681,80 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) | |||
1617 | return rc; | 1681 | return rc; |
1618 | } | 1682 | } |
1619 | 1683 | ||
1684 | static int | ||
1685 | qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply, | ||
1686 | unsigned long data) | ||
1687 | { | ||
1688 | struct qeth_ipa_cmd *cmd; | ||
1689 | __u16 rc; | ||
1690 | |||
1691 | QETH_DBF_TEXT(SETUP, 2, "diastrcb"); | ||
1692 | |||
1693 | cmd = (struct qeth_ipa_cmd *)data; | ||
1694 | rc = cmd->hdr.return_code; | ||
1695 | if (rc) | ||
1696 | QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc); | ||
1697 | switch (cmd->data.diagass.action) { | ||
1698 | case QETH_DIAGS_CMD_TRACE_QUERY: | ||
1699 | break; | ||
1700 | case QETH_DIAGS_CMD_TRACE_DISABLE: | ||
1701 | switch (rc) { | ||
1702 | case 0: | ||
1703 | case IPA_RC_INVALID_SUBCMD: | ||
1704 | card->info.promisc_mode = SET_PROMISC_MODE_OFF; | ||
1705 | dev_info(&card->gdev->dev, "The HiperSockets network " | ||
1706 | "traffic analyzer is deactivated\n"); | ||
1707 | break; | ||
1708 | default: | ||
1709 | break; | ||
1710 | } | ||
1711 | break; | ||
1712 | case QETH_DIAGS_CMD_TRACE_ENABLE: | ||
1713 | switch (rc) { | ||
1714 | case 0: | ||
1715 | card->info.promisc_mode = SET_PROMISC_MODE_ON; | ||
1716 | dev_info(&card->gdev->dev, "The HiperSockets network " | ||
1717 | "traffic analyzer is activated\n"); | ||
1718 | break; | ||
1719 | case IPA_RC_HARDWARE_AUTH_ERROR: | ||
1720 | dev_warn(&card->gdev->dev, "The device is not " | ||
1721 | "authorized to run as a HiperSockets network " | ||
1722 | "traffic analyzer\n"); | ||
1723 | break; | ||
1724 | case IPA_RC_TRACE_ALREADY_ACTIVE: | ||
1725 | dev_warn(&card->gdev->dev, "A HiperSockets " | ||
1726 | "network traffic analyzer is already " | ||
1727 | "active in the HiperSockets LAN\n"); | ||
1728 | break; | ||
1729 | default: | ||
1730 | break; | ||
1731 | } | ||
1732 | break; | ||
1733 | default: | ||
1734 | QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n", | ||
1735 | cmd->data.diagass.action, QETH_CARD_IFNAME(card)); | ||
1736 | } | ||
1737 | |||
1738 | return 0; | ||
1739 | } | ||
1740 | |||
1741 | static int | ||
1742 | qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) | ||
1743 | { | ||
1744 | struct qeth_cmd_buffer *iob; | ||
1745 | struct qeth_ipa_cmd *cmd; | ||
1746 | |||
1747 | QETH_DBF_TEXT(SETUP, 2, "diagtrac"); | ||
1748 | |||
1749 | iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); | ||
1750 | cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); | ||
1751 | cmd->data.diagass.subcmd_len = 16; | ||
1752 | cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE; | ||
1753 | cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET; | ||
1754 | cmd->data.diagass.action = diags_cmd; | ||
1755 | return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); | ||
1756 | } | ||
1757 | |||
1620 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, | 1758 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, |
1621 | struct net_device *dev) | 1759 | struct net_device *dev) |
1622 | { | 1760 | { |
@@ -1894,7 +2032,10 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
1894 | case QETH_CAST_ANYCAST: | 2032 | case QETH_CAST_ANYCAST: |
1895 | case QETH_CAST_NOCAST: | 2033 | case QETH_CAST_NOCAST: |
1896 | default: | 2034 | default: |
1897 | skb->pkt_type = PACKET_HOST; | 2035 | if (card->options.sniffer) |
2036 | skb->pkt_type = PACKET_OTHERHOST; | ||
2037 | else | ||
2038 | skb->pkt_type = PACKET_HOST; | ||
1898 | memcpy(tg_addr, card->dev->dev_addr, | 2039 | memcpy(tg_addr, card->dev->dev_addr, |
1899 | card->dev->addr_len); | 2040 | card->dev->addr_len); |
1900 | } | 2041 | } |
@@ -1950,7 +2091,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
1950 | int offset; | 2091 | int offset; |
1951 | __u16 vlan_tag = 0; | 2092 | __u16 vlan_tag = 0; |
1952 | unsigned int len; | 2093 | unsigned int len; |
1953 | |||
1954 | /* get first element of current buffer */ | 2094 | /* get first element of current buffer */ |
1955 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | 2095 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; |
1956 | offset = 0; | 2096 | offset = 0; |
@@ -1969,7 +2109,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
1969 | case QETH_HEADER_TYPE_LAYER3: | 2109 | case QETH_HEADER_TYPE_LAYER3: |
1970 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); | 2110 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); |
1971 | len = skb->len; | 2111 | len = skb->len; |
1972 | if (vlan_tag) | 2112 | if (vlan_tag && !card->options.sniffer) |
1973 | if (card->vlangrp) | 2113 | if (card->vlangrp) |
1974 | vlan_hwaccel_rx(skb, card->vlangrp, | 2114 | vlan_hwaccel_rx(skb, card->vlangrp, |
1975 | vlan_tag); | 2115 | vlan_tag); |
@@ -1980,6 +2120,16 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
1980 | else | 2120 | else |
1981 | netif_rx(skb); | 2121 | netif_rx(skb); |
1982 | break; | 2122 | break; |
2123 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ | ||
2124 | skb->pkt_type = PACKET_HOST; | ||
2125 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
2126 | if (card->options.checksum_type == NO_CHECKSUMMING) | ||
2127 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2128 | else | ||
2129 | skb->ip_summed = CHECKSUM_NONE; | ||
2130 | len = skb->len; | ||
2131 | netif_receive_skb(skb); | ||
2132 | break; | ||
1983 | default: | 2133 | default: |
1984 | dev_kfree_skb_any(skb); | 2134 | dev_kfree_skb_any(skb); |
1985 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); | 2135 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); |
@@ -2061,17 +2211,18 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2061 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 2211 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
2062 | 2212 | ||
2063 | qeth_set_allowed_threads(card, 0, 1); | 2213 | qeth_set_allowed_threads(card, 0, 1); |
2214 | if (card->options.sniffer && | ||
2215 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) | ||
2216 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2064 | if (card->read.state == CH_STATE_UP && | 2217 | if (card->read.state == CH_STATE_UP && |
2065 | card->write.state == CH_STATE_UP && | 2218 | card->write.state == CH_STATE_UP && |
2066 | (card->state == CARD_STATE_UP)) { | 2219 | (card->state == CARD_STATE_UP)) { |
2067 | if (recovery_mode) | 2220 | if (recovery_mode) |
2068 | qeth_l3_stop(card->dev); | 2221 | qeth_l3_stop(card->dev); |
2069 | else { | 2222 | else { |
2070 | if (card->dev) { | 2223 | rtnl_lock(); |
2071 | rtnl_lock(); | 2224 | dev_close(card->dev); |
2072 | dev_close(card->dev); | 2225 | rtnl_unlock(); |
2073 | rtnl_unlock(); | ||
2074 | } | ||
2075 | } | 2226 | } |
2076 | if (!card->use_hard_stop) { | 2227 | if (!card->use_hard_stop) { |
2077 | rc = qeth_send_stoplan(card); | 2228 | rc = qeth_send_stoplan(card); |
@@ -2105,6 +2256,36 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2105 | return rc; | 2256 | return rc; |
2106 | } | 2257 | } |
2107 | 2258 | ||
2259 | /* | ||
2260 | * test for and Switch promiscuous mode (on or off) | ||
2261 | * either for guestlan or HiperSocket Sniffer | ||
2262 | */ | ||
2263 | static void | ||
2264 | qeth_l3_handle_promisc_mode(struct qeth_card *card) | ||
2265 | { | ||
2266 | struct net_device *dev = card->dev; | ||
2267 | |||
2268 | if (((dev->flags & IFF_PROMISC) && | ||
2269 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) || | ||
2270 | (!(dev->flags & IFF_PROMISC) && | ||
2271 | (card->info.promisc_mode == SET_PROMISC_MODE_OFF))) | ||
2272 | return; | ||
2273 | |||
2274 | if (card->info.guestlan) { /* Guestlan trace */ | ||
2275 | if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | ||
2276 | qeth_setadp_promisc_mode(card); | ||
2277 | } else if (card->options.sniffer && /* HiperSockets trace */ | ||
2278 | qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) { | ||
2279 | if (dev->flags & IFF_PROMISC) { | ||
2280 | QETH_DBF_TEXT(TRACE, 3, "+promisc"); | ||
2281 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE); | ||
2282 | } else { | ||
2283 | QETH_DBF_TEXT(TRACE, 3, "-promisc"); | ||
2284 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2285 | } | ||
2286 | } | ||
2287 | } | ||
2288 | |||
2108 | static void qeth_l3_set_multicast_list(struct net_device *dev) | 2289 | static void qeth_l3_set_multicast_list(struct net_device *dev) |
2109 | { | 2290 | { |
2110 | struct qeth_card *card = dev->ml_priv; | 2291 | struct qeth_card *card = dev->ml_priv; |
@@ -2113,15 +2294,17 @@ static void qeth_l3_set_multicast_list(struct net_device *dev) | |||
2113 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && | 2294 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && |
2114 | (card->state != CARD_STATE_UP)) | 2295 | (card->state != CARD_STATE_UP)) |
2115 | return; | 2296 | return; |
2116 | qeth_l3_delete_mc_addresses(card); | 2297 | if (!card->options.sniffer) { |
2117 | qeth_l3_add_multicast_ipv4(card); | 2298 | qeth_l3_delete_mc_addresses(card); |
2299 | qeth_l3_add_multicast_ipv4(card); | ||
2118 | #ifdef CONFIG_QETH_IPV6 | 2300 | #ifdef CONFIG_QETH_IPV6 |
2119 | qeth_l3_add_multicast_ipv6(card); | 2301 | qeth_l3_add_multicast_ipv6(card); |
2120 | #endif | 2302 | #endif |
2121 | qeth_l3_set_ip_addr_list(card); | 2303 | qeth_l3_set_ip_addr_list(card); |
2122 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | 2304 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) |
2123 | return; | 2305 | return; |
2124 | qeth_setadp_promisc_mode(card); | 2306 | } |
2307 | qeth_l3_handle_promisc_mode(card); | ||
2125 | } | 2308 | } |
2126 | 2309 | ||
2127 | static const char *qeth_l3_arp_get_error_cause(int *rc) | 2310 | static const char *qeth_l3_arp_get_error_cause(int *rc) |
@@ -2684,6 +2867,24 @@ static void qeth_tx_csum(struct sk_buff *skb) | |||
2684 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | 2867 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); |
2685 | } | 2868 | } |
2686 | 2869 | ||
2870 | static inline int qeth_l3_tso_elements(struct sk_buff *skb) | ||
2871 | { | ||
2872 | unsigned long tcpd = (unsigned long)tcp_hdr(skb) + | ||
2873 | tcp_hdr(skb)->doff * 4; | ||
2874 | int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); | ||
2875 | int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd); | ||
2876 | elements += skb_shinfo(skb)->nr_frags; | ||
2877 | return elements; | ||
2878 | } | ||
2879 | |||
2880 | static inline int qeth_l3_tso_check(struct sk_buff *skb) | ||
2881 | { | ||
2882 | int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) - | ||
2883 | (unsigned long)skb->data; | ||
2884 | return (((unsigned long)skb->data & PAGE_MASK) != | ||
2885 | (((unsigned long)skb->data + len) & PAGE_MASK)); | ||
2886 | } | ||
2887 | |||
2687 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 2888 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
2688 | { | 2889 | { |
2689 | int rc; | 2890 | int rc; |
@@ -2702,9 +2903,8 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2702 | int data_offset = -1; | 2903 | int data_offset = -1; |
2703 | int nr_frags; | 2904 | int nr_frags; |
2704 | 2905 | ||
2705 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2906 | if (((card->info.type == QETH_CARD_TYPE_IQD) && (!ipv)) || |
2706 | (skb->protocol != htons(ETH_P_IPV6)) && | 2907 | card->options.sniffer) |
2707 | (skb->protocol != htons(ETH_P_IP))) | ||
2708 | goto tx_drop; | 2908 | goto tx_drop; |
2709 | 2909 | ||
2710 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 2910 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
@@ -2750,14 +2950,14 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2750 | if (data_offset < 0) | 2950 | if (data_offset < 0) |
2751 | skb_pull(new_skb, ETH_HLEN); | 2951 | skb_pull(new_skb, ETH_HLEN); |
2752 | } else { | 2952 | } else { |
2753 | if (new_skb->protocol == htons(ETH_P_IP)) { | 2953 | if (ipv == 4) { |
2754 | if (card->dev->type == ARPHRD_IEEE802_TR) | 2954 | if (card->dev->type == ARPHRD_IEEE802_TR) |
2755 | skb_pull(new_skb, TR_HLEN); | 2955 | skb_pull(new_skb, TR_HLEN); |
2756 | else | 2956 | else |
2757 | skb_pull(new_skb, ETH_HLEN); | 2957 | skb_pull(new_skb, ETH_HLEN); |
2758 | } | 2958 | } |
2759 | 2959 | ||
2760 | if (new_skb->protocol == ETH_P_IPV6 && card->vlangrp && | 2960 | if (ipv == 6 && card->vlangrp && |
2761 | vlan_tx_tag_present(new_skb)) { | 2961 | vlan_tx_tag_present(new_skb)) { |
2762 | skb_push(new_skb, VLAN_HLEN); | 2962 | skb_push(new_skb, VLAN_HLEN); |
2763 | skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); | 2963 | skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4); |
@@ -2777,16 +2977,21 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2777 | /* fix hardware limitation: as long as we do not have sbal | 2977 | /* fix hardware limitation: as long as we do not have sbal |
2778 | * chaining we can not send long frag lists | 2978 | * chaining we can not send long frag lists |
2779 | */ | 2979 | */ |
2780 | if ((large_send == QETH_LARGE_SEND_TSO) && | 2980 | if (large_send == QETH_LARGE_SEND_TSO) { |
2781 | ((skb_shinfo(new_skb)->nr_frags + 2) > 16)) { | 2981 | if (qeth_l3_tso_elements(new_skb) + 1 > 16) { |
2782 | if (skb_linearize(new_skb)) | 2982 | if (skb_linearize(new_skb)) |
2783 | goto tx_drop; | 2983 | goto tx_drop; |
2984 | if (card->options.performance_stats) | ||
2985 | card->perf_stats.tx_lin++; | ||
2986 | } | ||
2784 | } | 2987 | } |
2785 | 2988 | ||
2786 | if ((large_send == QETH_LARGE_SEND_TSO) && | 2989 | if ((large_send == QETH_LARGE_SEND_TSO) && |
2787 | (cast_type == RTN_UNSPEC)) { | 2990 | (cast_type == RTN_UNSPEC)) { |
2788 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 2991 | hdr = (struct qeth_hdr *)skb_push(new_skb, |
2789 | sizeof(struct qeth_hdr_tso)); | 2992 | sizeof(struct qeth_hdr_tso)); |
2993 | if (qeth_l3_tso_check(new_skb)) | ||
2994 | QETH_DBF_MESSAGE(2, "tso skb misaligned\n"); | ||
2790 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); | 2995 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); |
2791 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); | 2996 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); |
2792 | qeth_tso_fill_header(card, hdr, new_skb); | 2997 | qeth_tso_fill_header(card, hdr, new_skb); |
@@ -2903,46 +3108,28 @@ static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) | |||
2903 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) | 3108 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) |
2904 | { | 3109 | { |
2905 | struct qeth_card *card = dev->ml_priv; | 3110 | struct qeth_card *card = dev->ml_priv; |
2906 | enum qeth_card_states old_state; | ||
2907 | enum qeth_checksum_types csum_type; | 3111 | enum qeth_checksum_types csum_type; |
2908 | 3112 | ||
2909 | if ((card->state != CARD_STATE_UP) && | ||
2910 | (card->state != CARD_STATE_DOWN)) | ||
2911 | return -EPERM; | ||
2912 | |||
2913 | if (data) | 3113 | if (data) |
2914 | csum_type = HW_CHECKSUMMING; | 3114 | csum_type = HW_CHECKSUMMING; |
2915 | else | 3115 | else |
2916 | csum_type = SW_CHECKSUMMING; | 3116 | csum_type = SW_CHECKSUMMING; |
2917 | 3117 | ||
2918 | if (card->options.checksum_type != csum_type) { | 3118 | return qeth_l3_set_rx_csum(card, csum_type); |
2919 | old_state = card->state; | ||
2920 | if (card->state == CARD_STATE_UP) | ||
2921 | __qeth_l3_set_offline(card->gdev, 1); | ||
2922 | card->options.checksum_type = csum_type; | ||
2923 | if (old_state == CARD_STATE_UP) | ||
2924 | __qeth_l3_set_online(card->gdev, 1); | ||
2925 | } | ||
2926 | return 0; | ||
2927 | } | 3119 | } |
2928 | 3120 | ||
2929 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) | 3121 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) |
2930 | { | 3122 | { |
2931 | struct qeth_card *card = dev->ml_priv; | 3123 | struct qeth_card *card = dev->ml_priv; |
3124 | int rc = 0; | ||
2932 | 3125 | ||
2933 | if (data) { | 3126 | if (data) { |
2934 | if (card->options.large_send == QETH_LARGE_SEND_NO) { | 3127 | rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO); |
2935 | if (card->info.type == QETH_CARD_TYPE_IQD) | ||
2936 | return -EPERM; | ||
2937 | else | ||
2938 | card->options.large_send = QETH_LARGE_SEND_TSO; | ||
2939 | dev->features |= NETIF_F_TSO; | ||
2940 | } | ||
2941 | } else { | 3128 | } else { |
2942 | dev->features &= ~NETIF_F_TSO; | 3129 | dev->features &= ~NETIF_F_TSO; |
2943 | card->options.large_send = QETH_LARGE_SEND_NO; | 3130 | card->options.large_send = QETH_LARGE_SEND_NO; |
2944 | } | 3131 | } |
2945 | return 0; | 3132 | return rc; |
2946 | } | 3133 | } |
2947 | 3134 | ||
2948 | static const struct ethtool_ops qeth_l3_ethtool_ops = { | 3135 | static const struct ethtool_ops qeth_l3_ethtool_ops = { |
@@ -2957,7 +3144,7 @@ static const struct ethtool_ops qeth_l3_ethtool_ops = { | |||
2957 | .set_tso = qeth_l3_ethtool_set_tso, | 3144 | .set_tso = qeth_l3_ethtool_set_tso, |
2958 | .get_strings = qeth_core_get_strings, | 3145 | .get_strings = qeth_core_get_strings, |
2959 | .get_ethtool_stats = qeth_core_get_ethtool_stats, | 3146 | .get_ethtool_stats = qeth_core_get_ethtool_stats, |
2960 | .get_stats_count = qeth_core_get_stats_count, | 3147 | .get_sset_count = qeth_core_get_sset_count, |
2961 | .get_drvinfo = qeth_core_get_drvinfo, | 3148 | .get_drvinfo = qeth_core_get_drvinfo, |
2962 | .get_settings = qeth_core_ethtool_get_settings, | 3149 | .get_settings = qeth_core_ethtool_get_settings, |
2963 | }; | 3150 | }; |
@@ -3058,6 +3245,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
3058 | NETIF_F_HW_VLAN_RX | | 3245 | NETIF_F_HW_VLAN_RX | |
3059 | NETIF_F_HW_VLAN_FILTER; | 3246 | NETIF_F_HW_VLAN_FILTER; |
3060 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 3247 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
3248 | card->dev->gso_max_size = 15 * PAGE_SIZE; | ||
3061 | 3249 | ||
3062 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); | 3250 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); |
3063 | return register_netdev(card->dev); | 3251 | return register_netdev(card->dev); |
@@ -3092,7 +3280,7 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, | |||
3092 | index = i % QDIO_MAX_BUFFERS_PER_Q; | 3280 | index = i % QDIO_MAX_BUFFERS_PER_Q; |
3093 | buffer = &card->qdio.in_q->bufs[index]; | 3281 | buffer = &card->qdio.in_q->bufs[index]; |
3094 | if (!(qdio_err && | 3282 | if (!(qdio_err && |
3095 | qeth_check_qdio_errors(buffer->buffer, | 3283 | qeth_check_qdio_errors(card, buffer->buffer, |
3096 | qdio_err, "qinerr"))) | 3284 | qdio_err, "qinerr"))) |
3097 | qeth_l3_process_inbound_buffer(card, buffer, index); | 3285 | qeth_l3_process_inbound_buffer(card, buffer, index); |
3098 | /* clear buffer and give back to hardware */ | 3286 | /* clear buffer and give back to hardware */ |
@@ -3151,35 +3339,20 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3151 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); | 3339 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); |
3152 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 3340 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
3153 | 3341 | ||
3154 | qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); | ||
3155 | |||
3156 | recover_flag = card->state; | 3342 | recover_flag = card->state; |
3157 | rc = ccw_device_set_online(CARD_RDEV(card)); | ||
3158 | if (rc) { | ||
3159 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3160 | return -EIO; | ||
3161 | } | ||
3162 | rc = ccw_device_set_online(CARD_WDEV(card)); | ||
3163 | if (rc) { | ||
3164 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3165 | return -EIO; | ||
3166 | } | ||
3167 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
3168 | if (rc) { | ||
3169 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3170 | return -EIO; | ||
3171 | } | ||
3172 | |||
3173 | rc = qeth_core_hardsetup_card(card); | 3343 | rc = qeth_core_hardsetup_card(card); |
3174 | if (rc) { | 3344 | if (rc) { |
3175 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3345 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3346 | rc = -ENODEV; | ||
3176 | goto out_remove; | 3347 | goto out_remove; |
3177 | } | 3348 | } |
3178 | 3349 | ||
3179 | qeth_l3_query_ipassists(card, QETH_PROT_IPV4); | 3350 | qeth_l3_query_ipassists(card, QETH_PROT_IPV4); |
3180 | 3351 | ||
3181 | if (!card->dev && qeth_l3_setup_netdev(card)) | 3352 | if (!card->dev && qeth_l3_setup_netdev(card)) { |
3353 | rc = -ENODEV; | ||
3182 | goto out_remove; | 3354 | goto out_remove; |
3355 | } | ||
3183 | 3356 | ||
3184 | card->state = CARD_STATE_HARDSETUP; | 3357 | card->state = CARD_STATE_HARDSETUP; |
3185 | qeth_print_status_message(card); | 3358 | qeth_print_status_message(card); |
@@ -3196,28 +3369,32 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3196 | card->lan_online = 0; | 3369 | card->lan_online = 0; |
3197 | return 0; | 3370 | return 0; |
3198 | } | 3371 | } |
3372 | rc = -ENODEV; | ||
3199 | goto out_remove; | 3373 | goto out_remove; |
3200 | } else | 3374 | } else |
3201 | card->lan_online = 1; | 3375 | card->lan_online = 1; |
3202 | qeth_set_large_send(card, card->options.large_send); | ||
3203 | 3376 | ||
3204 | rc = qeth_l3_setadapter_parms(card); | 3377 | rc = qeth_l3_setadapter_parms(card); |
3205 | if (rc) | 3378 | if (rc) |
3206 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3379 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3207 | rc = qeth_l3_start_ipassists(card); | 3380 | if (!card->options.sniffer) { |
3208 | if (rc) | 3381 | rc = qeth_l3_start_ipassists(card); |
3209 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); | 3382 | if (rc) |
3210 | rc = qeth_l3_setrouting_v4(card); | 3383 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); |
3211 | if (rc) | 3384 | qeth_l3_set_large_send(card, card->options.large_send); |
3212 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); | 3385 | rc = qeth_l3_setrouting_v4(card); |
3213 | rc = qeth_l3_setrouting_v6(card); | 3386 | if (rc) |
3214 | if (rc) | 3387 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); |
3215 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | 3388 | rc = qeth_l3_setrouting_v6(card); |
3389 | if (rc) | ||
3390 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | ||
3391 | } | ||
3216 | netif_tx_disable(card->dev); | 3392 | netif_tx_disable(card->dev); |
3217 | 3393 | ||
3218 | rc = qeth_init_qdio_queues(card); | 3394 | rc = qeth_init_qdio_queues(card); |
3219 | if (rc) { | 3395 | if (rc) { |
3220 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); | 3396 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); |
3397 | rc = -ENODEV; | ||
3221 | goto out_remove; | 3398 | goto out_remove; |
3222 | } | 3399 | } |
3223 | card->state = CARD_STATE_SOFTSETUP; | 3400 | card->state = CARD_STATE_SOFTSETUP; |
@@ -3248,7 +3425,7 @@ out_remove: | |||
3248 | card->state = CARD_STATE_RECOVER; | 3425 | card->state = CARD_STATE_RECOVER; |
3249 | else | 3426 | else |
3250 | card->state = CARD_STATE_DOWN; | 3427 | card->state = CARD_STATE_DOWN; |
3251 | return -ENODEV; | 3428 | return rc; |
3252 | } | 3429 | } |
3253 | 3430 | ||
3254 | static int qeth_l3_set_online(struct ccwgroup_device *gdev) | 3431 | static int qeth_l3_set_online(struct ccwgroup_device *gdev) |
@@ -3358,11 +3535,9 @@ static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) | |||
3358 | if (card->state == CARD_STATE_RECOVER) { | 3535 | if (card->state == CARD_STATE_RECOVER) { |
3359 | rc = __qeth_l3_set_online(card->gdev, 1); | 3536 | rc = __qeth_l3_set_online(card->gdev, 1); |
3360 | if (rc) { | 3537 | if (rc) { |
3361 | if (card->dev) { | 3538 | rtnl_lock(); |
3362 | rtnl_lock(); | 3539 | dev_close(card->dev); |
3363 | dev_close(card->dev); | 3540 | rtnl_unlock(); |
3364 | rtnl_unlock(); | ||
3365 | } | ||
3366 | } | 3541 | } |
3367 | } else | 3542 | } else |
3368 | rc = __qeth_l3_set_online(card->gdev, 0); | 3543 | rc = __qeth_l3_set_online(card->gdev, 0); |
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index c144b9924d52..25b3e7aae44f 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c | |||
@@ -8,6 +8,8 @@ | |||
8 | * Frank Blaschka <frank.blaschka@de.ibm.com> | 8 | * Frank Blaschka <frank.blaschka@de.ibm.com> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/slab.h> | ||
12 | |||
11 | #include "qeth_l3.h" | 13 | #include "qeth_l3.h" |
12 | 14 | ||
13 | #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ | 15 | #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ |
@@ -293,31 +295,134 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev, | |||
293 | struct device_attribute *attr, const char *buf, size_t count) | 295 | struct device_attribute *attr, const char *buf, size_t count) |
294 | { | 296 | { |
295 | struct qeth_card *card = dev_get_drvdata(dev); | 297 | struct qeth_card *card = dev_get_drvdata(dev); |
298 | enum qeth_checksum_types csum_type; | ||
296 | char *tmp; | 299 | char *tmp; |
300 | int rc; | ||
297 | 301 | ||
298 | if (!card) | 302 | if (!card) |
299 | return -EINVAL; | 303 | return -EINVAL; |
300 | 304 | ||
301 | if ((card->state != CARD_STATE_DOWN) && | ||
302 | (card->state != CARD_STATE_RECOVER)) | ||
303 | return -EPERM; | ||
304 | |||
305 | tmp = strsep((char **) &buf, "\n"); | 305 | tmp = strsep((char **) &buf, "\n"); |
306 | if (!strcmp(tmp, "sw_checksumming")) | 306 | if (!strcmp(tmp, "sw_checksumming")) |
307 | card->options.checksum_type = SW_CHECKSUMMING; | 307 | csum_type = SW_CHECKSUMMING; |
308 | else if (!strcmp(tmp, "hw_checksumming")) | 308 | else if (!strcmp(tmp, "hw_checksumming")) |
309 | card->options.checksum_type = HW_CHECKSUMMING; | 309 | csum_type = HW_CHECKSUMMING; |
310 | else if (!strcmp(tmp, "no_checksumming")) | 310 | else if (!strcmp(tmp, "no_checksumming")) |
311 | card->options.checksum_type = NO_CHECKSUMMING; | 311 | csum_type = NO_CHECKSUMMING; |
312 | else { | 312 | else |
313 | return -EINVAL; | 313 | return -EINVAL; |
314 | } | 314 | |
315 | rc = qeth_l3_set_rx_csum(card, csum_type); | ||
316 | if (rc) | ||
317 | return rc; | ||
315 | return count; | 318 | return count; |
316 | } | 319 | } |
317 | 320 | ||
318 | static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, | 321 | static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, |
319 | qeth_l3_dev_checksum_store); | 322 | qeth_l3_dev_checksum_store); |
320 | 323 | ||
324 | static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, | ||
325 | struct device_attribute *attr, char *buf) | ||
326 | { | ||
327 | struct qeth_card *card = dev_get_drvdata(dev); | ||
328 | |||
329 | if (!card) | ||
330 | return -EINVAL; | ||
331 | |||
332 | return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0); | ||
333 | } | ||
334 | |||
335 | static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, | ||
336 | struct device_attribute *attr, const char *buf, size_t count) | ||
337 | { | ||
338 | struct qeth_card *card = dev_get_drvdata(dev); | ||
339 | int ret; | ||
340 | unsigned long i; | ||
341 | |||
342 | if (!card) | ||
343 | return -EINVAL; | ||
344 | |||
345 | if (card->info.type != QETH_CARD_TYPE_IQD) | ||
346 | return -EPERM; | ||
347 | |||
348 | if ((card->state != CARD_STATE_DOWN) && | ||
349 | (card->state != CARD_STATE_RECOVER)) | ||
350 | return -EPERM; | ||
351 | |||
352 | ret = strict_strtoul(buf, 16, &i); | ||
353 | if (ret) | ||
354 | return -EINVAL; | ||
355 | switch (i) { | ||
356 | case 0: | ||
357 | card->options.sniffer = i; | ||
358 | break; | ||
359 | case 1: | ||
360 | ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); | ||
361 | if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) { | ||
362 | card->options.sniffer = i; | ||
363 | if (card->qdio.init_pool.buf_count != | ||
364 | QETH_IN_BUF_COUNT_MAX) | ||
365 | qeth_realloc_buffer_pool(card, | ||
366 | QETH_IN_BUF_COUNT_MAX); | ||
367 | break; | ||
368 | } else | ||
369 | return -EPERM; | ||
370 | default: /* fall through */ | ||
371 | return -EINVAL; | ||
372 | } | ||
373 | return count; | ||
374 | } | ||
375 | |||
376 | static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, | ||
377 | qeth_l3_dev_sniffer_store); | ||
378 | |||
379 | static ssize_t qeth_l3_dev_large_send_show(struct device *dev, | ||
380 | struct device_attribute *attr, char *buf) | ||
381 | { | ||
382 | struct qeth_card *card = dev_get_drvdata(dev); | ||
383 | |||
384 | if (!card) | ||
385 | return -EINVAL; | ||
386 | |||
387 | switch (card->options.large_send) { | ||
388 | case QETH_LARGE_SEND_NO: | ||
389 | return sprintf(buf, "%s\n", "no"); | ||
390 | case QETH_LARGE_SEND_TSO: | ||
391 | return sprintf(buf, "%s\n", "TSO"); | ||
392 | default: | ||
393 | return sprintf(buf, "%s\n", "N/A"); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | static ssize_t qeth_l3_dev_large_send_store(struct device *dev, | ||
398 | struct device_attribute *attr, const char *buf, size_t count) | ||
399 | { | ||
400 | struct qeth_card *card = dev_get_drvdata(dev); | ||
401 | enum qeth_large_send_types type; | ||
402 | int rc = 0; | ||
403 | char *tmp; | ||
404 | |||
405 | if (!card) | ||
406 | return -EINVAL; | ||
407 | tmp = strsep((char **) &buf, "\n"); | ||
408 | if (!strcmp(tmp, "no")) | ||
409 | type = QETH_LARGE_SEND_NO; | ||
410 | else if (!strcmp(tmp, "TSO")) | ||
411 | type = QETH_LARGE_SEND_TSO; | ||
412 | else | ||
413 | return -EINVAL; | ||
414 | |||
415 | if (card->options.large_send == type) | ||
416 | return count; | ||
417 | rc = qeth_l3_set_large_send(card, type); | ||
418 | if (rc) | ||
419 | return rc; | ||
420 | return count; | ||
421 | } | ||
422 | |||
423 | static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show, | ||
424 | qeth_l3_dev_large_send_store); | ||
425 | |||
321 | static struct attribute *qeth_l3_device_attrs[] = { | 426 | static struct attribute *qeth_l3_device_attrs[] = { |
322 | &dev_attr_route4.attr, | 427 | &dev_attr_route4.attr, |
323 | &dev_attr_route6.attr, | 428 | &dev_attr_route6.attr, |
@@ -325,6 +430,8 @@ static struct attribute *qeth_l3_device_attrs[] = { | |||
325 | &dev_attr_broadcast_mode.attr, | 430 | &dev_attr_broadcast_mode.attr, |
326 | &dev_attr_canonical_macaddr.attr, | 431 | &dev_attr_canonical_macaddr.attr, |
327 | &dev_attr_checksumming.attr, | 432 | &dev_attr_checksumming.attr, |
433 | &dev_attr_sniffer.attr, | ||
434 | &dev_attr_large_send.attr, | ||
328 | NULL, | 435 | NULL, |
329 | }; | 436 | }; |
330 | 437 | ||
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 3012355f8304..70491274da16 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/slab.h> | ||
27 | #include <net/iucv/iucv.h> | 28 | #include <net/iucv/iucv.h> |
28 | #include <asm/cpcmd.h> | 29 | #include <asm/cpcmd.h> |
29 | #include <asm/ebcdic.h> | 30 | #include <asm/ebcdic.h> |
@@ -31,9 +32,9 @@ | |||
31 | 32 | ||
32 | struct smsg_callback { | 33 | struct smsg_callback { |
33 | struct list_head list; | 34 | struct list_head list; |
34 | char *prefix; | 35 | const char *prefix; |
35 | int len; | 36 | int len; |
36 | void (*callback)(char *from, char *str); | 37 | void (*callback)(const char *from, char *str); |
37 | }; | 38 | }; |
38 | 39 | ||
39 | MODULE_AUTHOR | 40 | MODULE_AUTHOR |
@@ -100,8 +101,8 @@ static void smsg_message_pending(struct iucv_path *path, | |||
100 | kfree(buffer); | 101 | kfree(buffer); |
101 | } | 102 | } |
102 | 103 | ||
103 | int smsg_register_callback(char *prefix, | 104 | int smsg_register_callback(const char *prefix, |
104 | void (*callback)(char *from, char *str)) | 105 | void (*callback)(const char *from, char *str)) |
105 | { | 106 | { |
106 | struct smsg_callback *cb; | 107 | struct smsg_callback *cb; |
107 | 108 | ||
@@ -117,8 +118,9 @@ int smsg_register_callback(char *prefix, | |||
117 | return 0; | 118 | return 0; |
118 | } | 119 | } |
119 | 120 | ||
120 | void smsg_unregister_callback(char *prefix, | 121 | void smsg_unregister_callback(const char *prefix, |
121 | void (*callback)(char *from, char *str)) | 122 | void (*callback)(const char *from, |
123 | char *str)) | ||
122 | { | 124 | { |
123 | struct smsg_callback *cb, *tmp; | 125 | struct smsg_callback *cb, *tmp; |
124 | 126 | ||
@@ -168,7 +170,7 @@ static int smsg_pm_restore_thaw(struct device *dev) | |||
168 | return 0; | 170 | return 0; |
169 | } | 171 | } |
170 | 172 | ||
171 | static struct dev_pm_ops smsg_pm_ops = { | 173 | static const struct dev_pm_ops smsg_pm_ops = { |
172 | .freeze = smsg_pm_freeze, | 174 | .freeze = smsg_pm_freeze, |
173 | .thaw = smsg_pm_restore_thaw, | 175 | .thaw = smsg_pm_restore_thaw, |
174 | .restore = smsg_pm_restore_thaw, | 176 | .restore = smsg_pm_restore_thaw, |
@@ -176,7 +178,7 @@ static struct dev_pm_ops smsg_pm_ops = { | |||
176 | 178 | ||
177 | static struct device_driver smsg_driver = { | 179 | static struct device_driver smsg_driver = { |
178 | .owner = THIS_MODULE, | 180 | .owner = THIS_MODULE, |
179 | .name = "SMSGIUCV", | 181 | .name = SMSGIUCV_DRV_NAME, |
180 | .bus = &iucv_bus, | 182 | .bus = &iucv_bus, |
181 | .pm = &smsg_pm_ops, | 183 | .pm = &smsg_pm_ops, |
182 | }; | 184 | }; |
diff --git a/drivers/s390/net/smsgiucv.h b/drivers/s390/net/smsgiucv.h index 67f5d4f8378d..149a1151608d 100644 --- a/drivers/s390/net/smsgiucv.h +++ b/drivers/s390/net/smsgiucv.h | |||
@@ -5,6 +5,10 @@ | |||
5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | 5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
6 | */ | 6 | */ |
7 | 7 | ||
8 | int smsg_register_callback(char *, void (*)(char *, char *)); | 8 | #define SMSGIUCV_DRV_NAME "SMSGIUCV" |
9 | void smsg_unregister_callback(char *, void (*)(char *, char *)); | 9 | |
10 | int smsg_register_callback(const char *, | ||
11 | void (*)(const char *, char *)); | ||
12 | void smsg_unregister_callback(const char *, | ||
13 | void (*)(const char *, char *)); | ||
10 | 14 | ||
diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c new file mode 100644 index 000000000000..137688790207 --- /dev/null +++ b/drivers/s390/net/smsgiucv_app.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * Deliver z/VM CP special messages (SMSG) as uevents. | ||
3 | * | ||
4 | * The driver registers for z/VM CP special messages with the | ||
5 | * "APP" prefix. Incoming messages are delivered to user space | ||
6 | * as uevents. | ||
7 | * | ||
8 | * Copyright IBM Corp. 2010 | ||
9 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | ||
10 | * | ||
11 | */ | ||
12 | #define KMSG_COMPONENT "smsgiucv_app" | ||
13 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
14 | |||
15 | #include <linux/ctype.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/kobject.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <net/iucv/iucv.h> | ||
25 | #include "smsgiucv.h" | ||
26 | |||
27 | /* prefix used for SMSG registration */ | ||
28 | #define SMSG_PREFIX "APP" | ||
29 | |||
30 | /* SMSG related uevent environment variables */ | ||
31 | #define ENV_SENDER_STR "SMSG_SENDER=" | ||
32 | #define ENV_SENDER_LEN (strlen(ENV_SENDER_STR) + 8 + 1) | ||
33 | #define ENV_PREFIX_STR "SMSG_ID=" | ||
34 | #define ENV_PREFIX_LEN (strlen(ENV_PREFIX_STR) + \ | ||
35 | strlen(SMSG_PREFIX) + 1) | ||
36 | #define ENV_TEXT_STR "SMSG_TEXT=" | ||
37 | #define ENV_TEXT_LEN(msg) (strlen(ENV_TEXT_STR) + strlen((msg)) + 1) | ||
38 | |||
39 | /* z/VM user ID which is permitted to send SMSGs | ||
40 | * If the value is undefined or empty (""), special messages are | ||
41 | * accepted from any z/VM user ID. */ | ||
42 | static char *sender; | ||
43 | module_param(sender, charp, 0400); | ||
44 | MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted"); | ||
45 | |||
46 | /* SMSG device representation */ | ||
47 | static struct device *smsg_app_dev; | ||
48 | |||
49 | /* list element for queuing received messages for delivery */ | ||
50 | struct smsg_app_event { | ||
51 | struct list_head list; | ||
52 | char *buf; | ||
53 | char *envp[4]; | ||
54 | }; | ||
55 | |||
56 | /* queue for outgoing uevents */ | ||
57 | static LIST_HEAD(smsg_event_queue); | ||
58 | static DEFINE_SPINLOCK(smsg_event_queue_lock); | ||
59 | |||
60 | static void smsg_app_event_free(struct smsg_app_event *ev) | ||
61 | { | ||
62 | kfree(ev->buf); | ||
63 | kfree(ev); | ||
64 | } | ||
65 | |||
66 | static struct smsg_app_event *smsg_app_event_alloc(const char *from, | ||
67 | const char *msg) | ||
68 | { | ||
69 | struct smsg_app_event *ev; | ||
70 | |||
71 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | ||
72 | if (!ev) | ||
73 | return NULL; | ||
74 | |||
75 | ev->buf = kzalloc(ENV_SENDER_LEN + ENV_PREFIX_LEN + | ||
76 | ENV_TEXT_LEN(msg), GFP_ATOMIC); | ||
77 | if (!ev->buf) { | ||
78 | kfree(ev); | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | /* setting up environment pointers into buf */ | ||
83 | ev->envp[0] = ev->buf; | ||
84 | ev->envp[1] = ev->envp[0] + ENV_SENDER_LEN; | ||
85 | ev->envp[2] = ev->envp[1] + ENV_PREFIX_LEN; | ||
86 | ev->envp[3] = NULL; | ||
87 | |||
88 | /* setting up environment: sender, prefix name, and message text */ | ||
89 | snprintf(ev->envp[0], ENV_SENDER_LEN, ENV_SENDER_STR "%s", from); | ||
90 | snprintf(ev->envp[1], ENV_PREFIX_LEN, ENV_PREFIX_STR "%s", SMSG_PREFIX); | ||
91 | snprintf(ev->envp[2], ENV_TEXT_LEN(msg), ENV_TEXT_STR "%s", msg); | ||
92 | |||
93 | return ev; | ||
94 | } | ||
95 | |||
96 | static void smsg_event_work_fn(struct work_struct *work) | ||
97 | { | ||
98 | LIST_HEAD(event_queue); | ||
99 | struct smsg_app_event *p, *n; | ||
100 | struct device *dev; | ||
101 | |||
102 | dev = get_device(smsg_app_dev); | ||
103 | if (!dev) | ||
104 | return; | ||
105 | |||
106 | spin_lock_bh(&smsg_event_queue_lock); | ||
107 | list_splice_init(&smsg_event_queue, &event_queue); | ||
108 | spin_unlock_bh(&smsg_event_queue_lock); | ||
109 | |||
110 | list_for_each_entry_safe(p, n, &event_queue, list) { | ||
111 | list_del(&p->list); | ||
112 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, p->envp); | ||
113 | smsg_app_event_free(p); | ||
114 | } | ||
115 | |||
116 | put_device(dev); | ||
117 | } | ||
118 | static DECLARE_WORK(smsg_event_work, smsg_event_work_fn); | ||
119 | |||
120 | static void smsg_app_callback(const char *from, char *msg) | ||
121 | { | ||
122 | struct smsg_app_event *se; | ||
123 | |||
124 | /* check if the originating z/VM user ID matches | ||
125 | * the configured sender. */ | ||
126 | if (sender && strlen(sender) > 0 && strcmp(from, sender) != 0) | ||
127 | return; | ||
128 | |||
129 | /* get start of message text (skip prefix and leading blanks) */ | ||
130 | msg += strlen(SMSG_PREFIX); | ||
131 | while (*msg && isspace(*msg)) | ||
132 | msg++; | ||
133 | if (*msg == '\0') | ||
134 | return; | ||
135 | |||
136 | /* allocate event list element and its environment */ | ||
137 | se = smsg_app_event_alloc(from, msg); | ||
138 | if (!se) | ||
139 | return; | ||
140 | |||
141 | /* queue event and schedule work function */ | ||
142 | spin_lock(&smsg_event_queue_lock); | ||
143 | list_add_tail(&se->list, &smsg_event_queue); | ||
144 | spin_unlock(&smsg_event_queue_lock); | ||
145 | |||
146 | schedule_work(&smsg_event_work); | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | static int __init smsgiucv_app_init(void) | ||
151 | { | ||
152 | struct device_driver *smsgiucv_drv; | ||
153 | int rc; | ||
154 | |||
155 | if (!MACHINE_IS_VM) | ||
156 | return -ENODEV; | ||
157 | |||
158 | smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL); | ||
159 | if (!smsg_app_dev) | ||
160 | return -ENOMEM; | ||
161 | |||
162 | smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus); | ||
163 | if (!smsgiucv_drv) { | ||
164 | kfree(smsg_app_dev); | ||
165 | return -ENODEV; | ||
166 | } | ||
167 | |||
168 | rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT); | ||
169 | if (rc) { | ||
170 | kfree(smsg_app_dev); | ||
171 | goto fail_put_driver; | ||
172 | } | ||
173 | smsg_app_dev->bus = &iucv_bus; | ||
174 | smsg_app_dev->parent = iucv_root; | ||
175 | smsg_app_dev->release = (void (*)(struct device *)) kfree; | ||
176 | smsg_app_dev->driver = smsgiucv_drv; | ||
177 | rc = device_register(smsg_app_dev); | ||
178 | if (rc) { | ||
179 | put_device(smsg_app_dev); | ||
180 | goto fail_put_driver; | ||
181 | } | ||
182 | |||
183 | /* register with the smsgiucv device driver */ | ||
184 | rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback); | ||
185 | if (rc) { | ||
186 | device_unregister(smsg_app_dev); | ||
187 | goto fail_put_driver; | ||
188 | } | ||
189 | |||
190 | rc = 0; | ||
191 | fail_put_driver: | ||
192 | put_driver(smsgiucv_drv); | ||
193 | return rc; | ||
194 | } | ||
195 | module_init(smsgiucv_app_init); | ||
196 | |||
197 | static void __exit smsgiucv_app_exit(void) | ||
198 | { | ||
199 | /* unregister callback */ | ||
200 | smsg_unregister_callback(SMSG_PREFIX, smsg_app_callback); | ||
201 | |||
202 | /* cancel pending work and flush any queued event work */ | ||
203 | cancel_work_sync(&smsg_event_work); | ||
204 | smsg_event_work_fn(&smsg_event_work); | ||
205 | |||
206 | device_unregister(smsg_app_dev); | ||
207 | } | ||
208 | module_exit(smsgiucv_app_exit); | ||
209 | |||
210 | MODULE_LICENSE("GPL v2"); | ||
211 | MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents"); | ||
212 | MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>"); | ||