aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/net')
-rw-r--r--drivers/s390/net/claw.c20
-rw-r--r--drivers/s390/net/ctcm_main.c43
-rw-r--r--drivers/s390/net/lcs.c74
-rw-r--r--drivers/s390/net/netiucv.c119
-rw-r--r--drivers/s390/net/qeth_core_main.c58
-rw-r--r--drivers/s390/net/qeth_core_mpc.c2
-rw-r--r--drivers/s390/net/qeth_core_mpc.h2
-rw-r--r--drivers/s390/net/qeth_l2_main.c88
-rw-r--r--drivers/s390/net/qeth_l3_main.c85
-rw-r--r--drivers/s390/net/smsgiucv.c63
10 files changed, 498 insertions, 56 deletions
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 30a43cc79e76..d40f7a934f94 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -3,12 +3,12 @@
3 * ESCON CLAW network driver 3 * ESCON CLAW network driver
4 * 4 *
5 * Linux for zSeries version 5 * Linux for zSeries version
6 * Copyright (C) 2002,2005 IBM Corporation 6 * Copyright IBM Corp. 2002, 2009
7 * Author(s) Original code written by: 7 * Author(s) Original code written by:
8 * Kazuo Iimura (iimura@jp.ibm.com) 8 * Kazuo Iimura <iimura@jp.ibm.com>
9 * Rewritten by 9 * Rewritten by
10 * Andy Richter (richtera@us.ibm.com) 10 * Andy Richter <richtera@us.ibm.com>
11 * Marc Price (mwprice@us.ibm.com) 11 * Marc Price <mwprice@us.ibm.com>
12 * 12 *
13 * sysfs parms: 13 * sysfs parms:
14 * group x.x.rrrr,x.x.wwww 14 * group x.x.rrrr,x.x.wwww
@@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev);
253/* Functions for unpack reads */ 253/* Functions for unpack reads */
254static void unpack_read(struct net_device *dev); 254static void unpack_read(struct net_device *dev);
255 255
256static int claw_pm_prepare(struct ccwgroup_device *gdev)
257{
258 return -EPERM;
259}
260
256/* ccwgroup table */ 261/* ccwgroup table */
257 262
258static struct ccwgroup_driver claw_group_driver = { 263static struct ccwgroup_driver claw_group_driver = {
@@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = {
264 .remove = claw_remove_device, 269 .remove = claw_remove_device,
265 .set_online = claw_new_device, 270 .set_online = claw_new_device,
266 .set_offline = claw_shutdown_device, 271 .set_offline = claw_shutdown_device,
272 .prepare = claw_pm_prepare,
267}; 273};
268 274
269/* 275/*
@@ -338,12 +344,6 @@ claw_tx(struct sk_buff *skb, struct net_device *dev)
338 344
339 CLAW_DBF_TEXT(4, trace, "claw_tx"); 345 CLAW_DBF_TEXT(4, trace, "claw_tx");
340 p_ch=&privptr->channel[WRITE]; 346 p_ch=&privptr->channel[WRITE];
341 if (skb == NULL) {
342 privptr->stats.tx_dropped++;
343 privptr->stats.tx_errors++;
344 CLAW_DBF_TEXT_(2, trace, "clawtx%d", -EIO);
345 return -EIO;
346 }
347 spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags); 347 spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags);
348 rc=claw_hw_tx( skb, dev, 1 ); 348 rc=claw_hw_tx( skb, dev, 1 );
349 spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); 349 spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags);
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 77f4033a0f4f..222e47394437 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * drivers/s390/net/ctcm_main.c 2 * drivers/s390/net/ctcm_main.c
3 * 3 *
4 * Copyright IBM Corp. 2001, 2007 4 * Copyright IBM Corp. 2001, 2009
5 * Author(s): 5 * Author(s):
6 * Original CTC driver(s): 6 * Original CTC driver(s):
7 * Fritz Elfert (felfert@millenux.com) 7 * Fritz Elfert (felfert@millenux.com)
@@ -1677,10 +1677,8 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev)
1677 BUG_ON(priv == NULL); 1677 BUG_ON(priv == NULL);
1678 1678
1679 CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, 1679 CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO,
1680 "removing device %s, r/w = %s/%s, proto : %d", 1680 "removing device %p, proto : %d",
1681 priv->channel[READ]->netdev->name, 1681 cgdev, priv->protocol);
1682 priv->channel[READ]->id, priv->channel[WRITE]->id,
1683 priv->protocol);
1684 1682
1685 if (cgdev->state == CCWGROUP_ONLINE) 1683 if (cgdev->state == CCWGROUP_ONLINE)
1686 ctcm_shutdown_device(cgdev); 1684 ctcm_shutdown_device(cgdev);
@@ -1690,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev)
1690 put_device(&cgdev->dev); 1688 put_device(&cgdev->dev);
1691} 1689}
1692 1690
1691static int ctcm_pm_suspend(struct ccwgroup_device *gdev)
1692{
1693 struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev);
1694
1695 if (gdev->state == CCWGROUP_OFFLINE)
1696 return 0;
1697 netif_device_detach(priv->channel[READ]->netdev);
1698 ctcm_close(priv->channel[READ]->netdev);
1699 ccw_device_set_offline(gdev->cdev[1]);
1700 ccw_device_set_offline(gdev->cdev[0]);
1701 return 0;
1702}
1703
1704static int ctcm_pm_resume(struct ccwgroup_device *gdev)
1705{
1706 struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev);
1707 int rc;
1708
1709 if (gdev->state == CCWGROUP_OFFLINE)
1710 return 0;
1711 rc = ccw_device_set_online(gdev->cdev[1]);
1712 if (rc)
1713 goto err_out;
1714 rc = ccw_device_set_online(gdev->cdev[0]);
1715 if (rc)
1716 goto err_out;
1717 ctcm_open(priv->channel[READ]->netdev);
1718err_out:
1719 netif_device_attach(priv->channel[READ]->netdev);
1720 return rc;
1721}
1722
1693static struct ccwgroup_driver ctcm_group_driver = { 1723static struct ccwgroup_driver ctcm_group_driver = {
1694 .owner = THIS_MODULE, 1724 .owner = THIS_MODULE,
1695 .name = CTC_DRIVER_NAME, 1725 .name = CTC_DRIVER_NAME,
@@ -1699,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = {
1699 .remove = ctcm_remove_device, 1729 .remove = ctcm_remove_device,
1700 .set_online = ctcm_new_device, 1730 .set_online = ctcm_new_device,
1701 .set_offline = ctcm_shutdown_device, 1731 .set_offline = ctcm_shutdown_device,
1732 .freeze = ctcm_pm_suspend,
1733 .thaw = ctcm_pm_resume,
1734 .restore = ctcm_pm_resume,
1702}; 1735};
1703 1736
1704 1737
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index a45bc24eb5f9..07a25c3f94b6 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1,15 +1,12 @@
1/* 1/*
2 * linux/drivers/s390/net/lcs.c
3 *
4 * Linux for S/390 Lan Channel Station Network Driver 2 * Linux for S/390 Lan Channel Station Network Driver
5 * 3 *
6 * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, 4 * Copyright IBM Corp. 1999, 2009
7 * IBM Corporation 5 * Author(s): Original Code written by
8 * Author(s): Original Code written by 6 * DJ Barrow <djbarrow@de.ibm.com,barrow_dj@yahoo.com>
9 * DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 7 * Rewritten by
10 * Rewritten by 8 * Frank Pavlic <fpavlic@de.ibm.com> and
11 * Frank Pavlic (fpavlic@de.ibm.com) and 9 * Martin Schwidefsky <schwidefsky@de.ibm.com>
12 * Martin Schwidefsky <schwidefsky@de.ibm.com>
13 * 10 *
14 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by 12 * it under the terms of the GNU General Public License as published by
@@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
2313 put_device(&ccwgdev->dev); 2310 put_device(&ccwgdev->dev);
2314} 2311}
2315 2312
2313static int lcs_pm_suspend(struct lcs_card *card)
2314{
2315 if (card->dev)
2316 netif_device_detach(card->dev);
2317 lcs_set_allowed_threads(card, 0);
2318 lcs_wait_for_threads(card, 0xffffffff);
2319 if (card->state != DEV_STATE_DOWN)
2320 __lcs_shutdown_device(card->gdev, 1);
2321 return 0;
2322}
2323
2324static int lcs_pm_resume(struct lcs_card *card)
2325{
2326 int rc = 0;
2327
2328 if (card->state == DEV_STATE_RECOVER)
2329 rc = lcs_new_device(card->gdev);
2330 if (card->dev)
2331 netif_device_attach(card->dev);
2332 if (rc) {
2333 dev_warn(&card->gdev->dev, "The lcs device driver "
2334 "failed to recover the device\n");
2335 }
2336 return rc;
2337}
2338
2339static int lcs_prepare(struct ccwgroup_device *gdev)
2340{
2341 return 0;
2342}
2343
2344static void lcs_complete(struct ccwgroup_device *gdev)
2345{
2346 return;
2347}
2348
2349static int lcs_freeze(struct ccwgroup_device *gdev)
2350{
2351 struct lcs_card *card = dev_get_drvdata(&gdev->dev);
2352 return lcs_pm_suspend(card);
2353}
2354
2355static int lcs_thaw(struct ccwgroup_device *gdev)
2356{
2357 struct lcs_card *card = dev_get_drvdata(&gdev->dev);
2358 return lcs_pm_resume(card);
2359}
2360
2361static int lcs_restore(struct ccwgroup_device *gdev)
2362{
2363 struct lcs_card *card = dev_get_drvdata(&gdev->dev);
2364 return lcs_pm_resume(card);
2365}
2366
2316/** 2367/**
2317 * LCS ccwgroup driver registration 2368 * LCS ccwgroup driver registration
2318 */ 2369 */
@@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = {
2325 .remove = lcs_remove_device, 2376 .remove = lcs_remove_device,
2326 .set_online = lcs_new_device, 2377 .set_online = lcs_new_device,
2327 .set_offline = lcs_shutdown_device, 2378 .set_offline = lcs_shutdown_device,
2379 .prepare = lcs_prepare,
2380 .complete = lcs_complete,
2381 .freeze = lcs_freeze,
2382 .thaw = lcs_thaw,
2383 .restore = lcs_restore,
2328}; 2384};
2329 2385
2330/** 2386/**
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index be716e45f7ac..fdb02d043d3e 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1,11 +1,15 @@
1/* 1/*
2 * IUCV network driver 2 * IUCV network driver
3 * 3 *
4 * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation 4 * Copyright IBM Corp. 2001, 2009
5 * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
6 * 5 *
7 * Sysfs integration and all bugs therein by Cornelia Huck 6 * Author(s):
8 * (cornelia.huck@de.ibm.com) 7 * Original netiucv driver:
8 * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
9 * Sysfs integration and all bugs therein:
10 * Cornelia Huck (cornelia.huck@de.ibm.com)
11 * PM functions:
12 * Ursula Braun (ursula.braun@de.ibm.com)
9 * 13 *
10 * Documentation used: 14 * Documentation used:
11 * the source of the original IUCV driver by: 15 * the source of the original IUCV driver by:
@@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
149 153
150#define PRINTK_HEADER " iucv: " /* for debugging */ 154#define PRINTK_HEADER " iucv: " /* for debugging */
151 155
156/* dummy device to make sure netiucv_pm functions are called */
157static struct device *netiucv_dev;
158
159static int netiucv_pm_prepare(struct device *);
160static void netiucv_pm_complete(struct device *);
161static int netiucv_pm_freeze(struct device *);
162static int netiucv_pm_restore_thaw(struct device *);
163
164static struct dev_pm_ops netiucv_pm_ops = {
165 .prepare = netiucv_pm_prepare,
166 .complete = netiucv_pm_complete,
167 .freeze = netiucv_pm_freeze,
168 .thaw = netiucv_pm_restore_thaw,
169 .restore = netiucv_pm_restore_thaw,
170};
171
152static struct device_driver netiucv_driver = { 172static struct device_driver netiucv_driver = {
153 .owner = THIS_MODULE, 173 .owner = THIS_MODULE,
154 .name = "netiucv", 174 .name = "netiucv",
155 .bus = &iucv_bus, 175 .bus = &iucv_bus,
176 .pm = &netiucv_pm_ops,
156}; 177};
157 178
158static int netiucv_callback_connreq(struct iucv_path *, 179static int netiucv_callback_connreq(struct iucv_path *,
@@ -233,6 +254,7 @@ struct netiucv_priv {
233 fsm_instance *fsm; 254 fsm_instance *fsm;
234 struct iucv_connection *conn; 255 struct iucv_connection *conn;
235 struct device *dev; 256 struct device *dev;
257 int pm_state;
236}; 258};
237 259
238/** 260/**
@@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev)
1265 return 0; 1287 return 0;
1266} 1288}
1267 1289
1290static int netiucv_pm_prepare(struct device *dev)
1291{
1292 IUCV_DBF_TEXT(trace, 3, __func__);
1293 return 0;
1294}
1295
1296static void netiucv_pm_complete(struct device *dev)
1297{
1298 IUCV_DBF_TEXT(trace, 3, __func__);
1299 return;
1300}
1301
1302/**
1303 * netiucv_pm_freeze() - Freeze PM callback
1304 * @dev: netiucv device
1305 *
1306 * close open netiucv interfaces
1307 */
1308static int netiucv_pm_freeze(struct device *dev)
1309{
1310 struct netiucv_priv *priv = dev->driver_data;
1311 struct net_device *ndev = NULL;
1312 int rc = 0;
1313
1314 IUCV_DBF_TEXT(trace, 3, __func__);
1315 if (priv && priv->conn)
1316 ndev = priv->conn->netdev;
1317 if (!ndev)
1318 goto out;
1319 netif_device_detach(ndev);
1320 priv->pm_state = fsm_getstate(priv->fsm);
1321 rc = netiucv_close(ndev);
1322out:
1323 return rc;
1324}
1325
1326/**
1327 * netiucv_pm_restore_thaw() - Thaw and restore PM callback
1328 * @dev: netiucv device
1329 *
1330 * re-open netiucv interfaces closed during freeze
1331 */
1332static int netiucv_pm_restore_thaw(struct device *dev)
1333{
1334 struct netiucv_priv *priv = dev->driver_data;
1335 struct net_device *ndev = NULL;
1336 int rc = 0;
1337
1338 IUCV_DBF_TEXT(trace, 3, __func__);
1339 if (priv && priv->conn)
1340 ndev = priv->conn->netdev;
1341 if (!ndev)
1342 goto out;
1343 switch (priv->pm_state) {
1344 case DEV_STATE_RUNNING:
1345 case DEV_STATE_STARTWAIT:
1346 rc = netiucv_open(ndev);
1347 break;
1348 default:
1349 break;
1350 }
1351 netif_device_attach(ndev);
1352out:
1353 return rc;
1354}
1355
1268/** 1356/**
1269 * Start transmission of a packet. 1357 * Start transmission of a packet.
1270 * Called from generic network device layer. 1358 * Called from generic network device layer.
@@ -1315,9 +1403,9 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
1315 return NETDEV_TX_BUSY; 1403 return NETDEV_TX_BUSY;
1316 } 1404 }
1317 dev->trans_start = jiffies; 1405 dev->trans_start = jiffies;
1318 rc = netiucv_transmit_skb(privptr->conn, skb) != 0; 1406 rc = netiucv_transmit_skb(privptr->conn, skb);
1319 netiucv_clear_busy(dev); 1407 netiucv_clear_busy(dev);
1320 return rc; 1408 return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK;
1321} 1409}
1322 1410
1323/** 1411/**
@@ -1731,7 +1819,6 @@ static int netiucv_register_device(struct net_device *ndev)
1731 struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); 1819 struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
1732 int ret; 1820 int ret;
1733 1821
1734
1735 IUCV_DBF_TEXT(trace, 3, __func__); 1822 IUCV_DBF_TEXT(trace, 3, __func__);
1736 1823
1737 if (dev) { 1824 if (dev) {
@@ -2100,6 +2187,7 @@ static void __exit netiucv_exit(void)
2100 netiucv_unregister_device(dev); 2187 netiucv_unregister_device(dev);
2101 } 2188 }
2102 2189
2190 device_unregister(netiucv_dev);
2103 driver_unregister(&netiucv_driver); 2191 driver_unregister(&netiucv_driver);
2104 iucv_unregister(&netiucv_handler, 1); 2192 iucv_unregister(&netiucv_handler, 1);
2105 iucv_unregister_dbf_views(); 2193 iucv_unregister_dbf_views();
@@ -2125,10 +2213,25 @@ static int __init netiucv_init(void)
2125 IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); 2213 IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
2126 goto out_iucv; 2214 goto out_iucv;
2127 } 2215 }
2128 2216 /* establish dummy device */
2217 netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
2218 if (!netiucv_dev) {
2219 rc = -ENOMEM;
2220 goto out_driver;
2221 }
2222 dev_set_name(netiucv_dev, "netiucv");
2223 netiucv_dev->bus = &iucv_bus;
2224 netiucv_dev->parent = iucv_root;
2225 netiucv_dev->release = (void (*)(struct device *))kfree;
2226 netiucv_dev->driver = &netiucv_driver;
2227 rc = device_register(netiucv_dev);
2228 if (rc)
2229 goto out_driver;
2129 netiucv_banner(); 2230 netiucv_banner();
2130 return rc; 2231 return rc;
2131 2232
2233out_driver:
2234 driver_unregister(&netiucv_driver);
2132out_iucv: 2235out_iucv:
2133 iucv_unregister(&netiucv_handler, 1); 2236 iucv_unregister(&netiucv_handler, 1);
2134out_dbf: 2237out_dbf:
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index c827d69b5a91..d53621c4acbb 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * drivers/s390/net/qeth_core_main.c 2 * drivers/s390/net/qeth_core_main.c
3 * 3 *
4 * Copyright IBM Corp. 2007 4 * Copyright IBM Corp. 2007, 2009
5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, 5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
6 * Frank Pavlic <fpavlic@de.ibm.com>, 6 * Frank Pavlic <fpavlic@de.ibm.com>,
7 * Thomas Spatzier <tspat@de.ibm.com>, 7 * Thomas Spatzier <tspat@de.ibm.com>,
@@ -952,6 +952,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
952 buf->buffer->element[i].addr = NULL; 952 buf->buffer->element[i].addr = NULL;
953 buf->buffer->element[i].flags = 0; 953 buf->buffer->element[i].flags = 0;
954 } 954 }
955 buf->buffer->element[15].flags = 0;
955 buf->next_element_to_fill = 0; 956 buf->next_element_to_fill = 0;
956 atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); 957 atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
957} 958}
@@ -1140,6 +1141,8 @@ static int qeth_setup_card(struct qeth_card *card)
1140 card->ipato.enabled = 0; 1141 card->ipato.enabled = 0;
1141 card->ipato.invert4 = 0; 1142 card->ipato.invert4 = 0;
1142 card->ipato.invert6 = 0; 1143 card->ipato.invert6 = 0;
1144 if (card->info.type == QETH_CARD_TYPE_IQD)
1145 card->options.checksum_type = NO_CHECKSUMMING;
1143 /* init QDIO stuff */ 1146 /* init QDIO stuff */
1144 qeth_init_qdio_info(card); 1147 qeth_init_qdio_info(card);
1145 return 0; 1148 return 0;
@@ -2934,8 +2937,8 @@ int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
2934 if (card->info.type == QETH_CARD_TYPE_OSN) 2937 if (card->info.type == QETH_CARD_TYPE_OSN)
2935 return cast_type; 2938 return cast_type;
2936 2939
2937 if (skb->dst && skb->dst->neighbour) { 2940 if (skb_dst(skb) && skb_dst(skb)->neighbour) {
2938 cast_type = skb->dst->neighbour->type; 2941 cast_type = skb_dst(skb)->neighbour->type;
2939 if ((cast_type == RTN_BROADCAST) || 2942 if ((cast_type == RTN_BROADCAST) ||
2940 (cast_type == RTN_MULTICAST) || 2943 (cast_type == RTN_MULTICAST) ||
2941 (cast_type == RTN_ANYCAST)) 2944 (cast_type == RTN_ANYCAST))
@@ -4192,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev)
4192 card->discipline.ccwgdriver->shutdown(gdev); 4195 card->discipline.ccwgdriver->shutdown(gdev);
4193} 4196}
4194 4197
4198static int qeth_core_prepare(struct ccwgroup_device *gdev)
4199{
4200 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
4201 if (card->discipline.ccwgdriver &&
4202 card->discipline.ccwgdriver->prepare)
4203 return card->discipline.ccwgdriver->prepare(gdev);
4204 return 0;
4205}
4206
4207static void qeth_core_complete(struct ccwgroup_device *gdev)
4208{
4209 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
4210 if (card->discipline.ccwgdriver &&
4211 card->discipline.ccwgdriver->complete)
4212 card->discipline.ccwgdriver->complete(gdev);
4213}
4214
4215static int qeth_core_freeze(struct ccwgroup_device *gdev)
4216{
4217 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
4218 if (card->discipline.ccwgdriver &&
4219 card->discipline.ccwgdriver->freeze)
4220 return card->discipline.ccwgdriver->freeze(gdev);
4221 return 0;
4222}
4223
4224static int qeth_core_thaw(struct ccwgroup_device *gdev)
4225{
4226 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
4227 if (card->discipline.ccwgdriver &&
4228 card->discipline.ccwgdriver->thaw)
4229 return card->discipline.ccwgdriver->thaw(gdev);
4230 return 0;
4231}
4232
4233static int qeth_core_restore(struct ccwgroup_device *gdev)
4234{
4235 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
4236 if (card->discipline.ccwgdriver &&
4237 card->discipline.ccwgdriver->restore)
4238 return card->discipline.ccwgdriver->restore(gdev);
4239 return 0;
4240}
4241
4195static struct ccwgroup_driver qeth_core_ccwgroup_driver = { 4242static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
4196 .owner = THIS_MODULE, 4243 .owner = THIS_MODULE,
4197 .name = "qeth", 4244 .name = "qeth",
@@ -4201,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
4201 .set_online = qeth_core_set_online, 4248 .set_online = qeth_core_set_online,
4202 .set_offline = qeth_core_set_offline, 4249 .set_offline = qeth_core_set_offline,
4203 .shutdown = qeth_core_shutdown, 4250 .shutdown = qeth_core_shutdown,
4251 .prepare = qeth_core_prepare,
4252 .complete = qeth_core_complete,
4253 .freeze = qeth_core_freeze,
4254 .thaw = qeth_core_thaw,
4255 .restore = qeth_core_restore,
4204}; 4256};
4205 4257
4206static ssize_t 4258static ssize_t
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c
index 06f4de1f0507..ec24901c802c 100644
--- a/drivers/s390/net/qeth_core_mpc.c
+++ b/drivers/s390/net/qeth_core_mpc.c
@@ -181,6 +181,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
181 {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, 181 {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"},
182 {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, 182 {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"},
183 {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, 183 {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"},
184 {IPA_RC_L2_MAC_NOT_AUTH_BY_HYP, "L2 mac not authorized by hypervisor"},
185 {IPA_RC_L2_MAC_NOT_AUTH_BY_ADP, "L2 mac not authorized by adapter"},
184 {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, 186 {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"},
185 {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, 187 {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"},
186 {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, 188 {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"},
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 18548822e37c..eecb2ee62e85 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -168,6 +168,8 @@ enum qeth_ipa_return_codes {
168 IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, 168 IPA_RC_L2_ADDR_TABLE_FULL = 0x2006,
169 IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, 169 IPA_RC_L2_DUP_LAYER3_MAC = 0x200a,
170 IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, 170 IPA_RC_L2_GMAC_NOT_FOUND = 0x200b,
171 IPA_RC_L2_MAC_NOT_AUTH_BY_HYP = 0x200c,
172 IPA_RC_L2_MAC_NOT_AUTH_BY_ADP = 0x200d,
171 IPA_RC_L2_MAC_NOT_FOUND = 0x2010, 173 IPA_RC_L2_MAC_NOT_FOUND = 0x2010,
172 IPA_RC_L2_INVALID_VLAN_ID = 0x2015, 174 IPA_RC_L2_INVALID_VLAN_ID = 0x2015,
173 IPA_RC_L2_DUP_VLAN_ID = 0x2016, 175 IPA_RC_L2_DUP_VLAN_ID = 0x2016,
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 172031baedc1..81d7f268418a 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * drivers/s390/net/qeth_l2_main.c 2 * drivers/s390/net/qeth_l2_main.c
3 * 3 *
4 * Copyright IBM Corp. 2007 4 * Copyright IBM Corp. 2007, 2009
5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, 5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
6 * Frank Pavlic <fpavlic@de.ibm.com>, 6 * Frank Pavlic <fpavlic@de.ibm.com>,
7 * Thomas Spatzier <tspat@de.ibm.com>, 7 * Thomas Spatzier <tspat@de.ibm.com>,
@@ -19,6 +19,7 @@
19#include <linux/etherdevice.h> 19#include <linux/etherdevice.h>
20#include <linux/mii.h> 20#include <linux/mii.h>
21#include <linux/ip.h> 21#include <linux/ip.h>
22#include <linux/list.h>
22 23
23#include "qeth_core.h" 24#include "qeth_core.h"
24 25
@@ -130,7 +131,7 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card,
130 cmd = (struct qeth_ipa_cmd *) data; 131 cmd = (struct qeth_ipa_cmd *) data;
131 mac = &cmd->data.setdelmac.mac[0]; 132 mac = &cmd->data.setdelmac.mac[0];
132 /* MAC already registered, needed in couple/uncouple case */ 133 /* MAC already registered, needed in couple/uncouple case */
133 if (cmd->hdr.return_code == 0x2005) { 134 if (cmd->hdr.return_code == IPA_RC_L2_DUP_MAC) {
134 QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", 135 QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n",
135 mac, QETH_CARD_IFNAME(card)); 136 mac, QETH_CARD_IFNAME(card));
136 cmd->hdr.return_code = 0; 137 cmd->hdr.return_code = 0;
@@ -502,6 +503,30 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
502 if (cmd->hdr.return_code) { 503 if (cmd->hdr.return_code) {
503 QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); 504 QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code);
504 card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; 505 card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
506 switch (cmd->hdr.return_code) {
507 case IPA_RC_L2_DUP_MAC:
508 case IPA_RC_L2_DUP_LAYER3_MAC:
509 dev_warn(&card->gdev->dev,
510 "MAC address "
511 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
512 "already exists\n",
513 card->dev->dev_addr[0], card->dev->dev_addr[1],
514 card->dev->dev_addr[2], card->dev->dev_addr[3],
515 card->dev->dev_addr[4], card->dev->dev_addr[5]);
516 break;
517 case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
518 case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
519 dev_warn(&card->gdev->dev,
520 "MAC address "
521 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
522 "is not authorized\n",
523 card->dev->dev_addr[0], card->dev->dev_addr[1],
524 card->dev->dev_addr[2], card->dev->dev_addr[3],
525 card->dev->dev_addr[4], card->dev->dev_addr[5]);
526 break;
527 default:
528 break;
529 }
505 cmd->hdr.return_code = -EIO; 530 cmd->hdr.return_code = -EIO;
506 } else { 531 } else {
507 card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; 532 card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
@@ -616,6 +641,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
616{ 641{
617 struct qeth_card *card = dev->ml_priv; 642 struct qeth_card *card = dev->ml_priv;
618 struct dev_addr_list *dm; 643 struct dev_addr_list *dm;
644 struct netdev_hw_addr *ha;
619 645
620 if (card->info.type == QETH_CARD_TYPE_OSN) 646 if (card->info.type == QETH_CARD_TYPE_OSN)
621 return ; 647 return ;
@@ -629,8 +655,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
629 for (dm = dev->mc_list; dm; dm = dm->next) 655 for (dm = dev->mc_list; dm; dm = dm->next)
630 qeth_l2_add_mc(card, dm->da_addr, 0); 656 qeth_l2_add_mc(card, dm->da_addr, 0);
631 657
632 for (dm = dev->uc_list; dm; dm = dm->next) 658 list_for_each_entry(ha, &dev->uc_list, list)
633 qeth_l2_add_mc(card, dm->da_addr, 1); 659 qeth_l2_add_mc(card, ha->addr, 1);
634 660
635 spin_unlock_bh(&card->mclock); 661 spin_unlock_bh(&card->mclock);
636 if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) 662 if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
@@ -839,6 +865,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
839{ 865{
840 struct qeth_card *card = dev_get_drvdata(&cgdev->dev); 866 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
841 867
868 qeth_set_allowed_threads(card, 0, 1);
842 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); 869 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
843 870
844 if (cgdev->state == CCWGROUP_ONLINE) { 871 if (cgdev->state == CCWGROUP_ONLINE) {
@@ -974,8 +1001,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
974 dev_warn(&card->gdev->dev, 1001 dev_warn(&card->gdev->dev,
975 "The LAN is offline\n"); 1002 "The LAN is offline\n");
976 card->lan_online = 0; 1003 card->lan_online = 0;
1004 return 0;
977 } 1005 }
978 return rc; 1006 goto out_remove;
979 } else 1007 } else
980 card->lan_online = 1; 1008 card->lan_online = 1;
981 1009
@@ -1113,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
1113 qeth_clear_qdio_buffers(card); 1141 qeth_clear_qdio_buffers(card);
1114} 1142}
1115 1143
1144static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
1145{
1146 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
1147
1148 if (card->dev)
1149 netif_device_detach(card->dev);
1150 qeth_set_allowed_threads(card, 0, 1);
1151 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
1152 if (gdev->state == CCWGROUP_OFFLINE)
1153 return 0;
1154 if (card->state == CARD_STATE_UP) {
1155 card->use_hard_stop = 1;
1156 __qeth_l2_set_offline(card->gdev, 1);
1157 } else
1158 __qeth_l2_set_offline(card->gdev, 0);
1159 return 0;
1160}
1161
1162static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
1163{
1164 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
1165 int rc = 0;
1166
1167 if (gdev->state == CCWGROUP_OFFLINE)
1168 goto out;
1169
1170 if (card->state == CARD_STATE_RECOVER) {
1171 rc = __qeth_l2_set_online(card->gdev, 1);
1172 if (rc) {
1173 if (card->dev) {
1174 rtnl_lock();
1175 dev_close(card->dev);
1176 rtnl_unlock();
1177 }
1178 }
1179 } else
1180 rc = __qeth_l2_set_online(card->gdev, 0);
1181out:
1182 qeth_set_allowed_threads(card, 0xffffffff, 0);
1183 if (card->dev)
1184 netif_device_attach(card->dev);
1185 if (rc)
1186 dev_warn(&card->gdev->dev, "The qeth device driver "
1187 "failed to recover an error on the device\n");
1188 return rc;
1189}
1190
1116struct ccwgroup_driver qeth_l2_ccwgroup_driver = { 1191struct ccwgroup_driver qeth_l2_ccwgroup_driver = {
1117 .probe = qeth_l2_probe_device, 1192 .probe = qeth_l2_probe_device,
1118 .remove = qeth_l2_remove_device, 1193 .remove = qeth_l2_remove_device,
1119 .set_online = qeth_l2_set_online, 1194 .set_online = qeth_l2_set_online,
1120 .set_offline = qeth_l2_set_offline, 1195 .set_offline = qeth_l2_set_offline,
1121 .shutdown = qeth_l2_shutdown, 1196 .shutdown = qeth_l2_shutdown,
1197 .freeze = qeth_l2_pm_suspend,
1198 .thaw = qeth_l2_pm_resume,
1199 .restore = qeth_l2_pm_resume,
1122}; 1200};
1123EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); 1201EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver);
1124 1202
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 0ba3817cb6a7..54872406864e 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * drivers/s390/net/qeth_l3_main.c 2 * drivers/s390/net/qeth_l3_main.c
3 * 3 *
4 * Copyright IBM Corp. 2007 4 * Copyright IBM Corp. 2007, 2009
5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, 5 * Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
6 * Frank Pavlic <fpavlic@de.ibm.com>, 6 * Frank Pavlic <fpavlic@de.ibm.com>,
7 * Thomas Spatzier <tspat@de.ibm.com>, 7 * Thomas Spatzier <tspat@de.ibm.com>,
@@ -1920,16 +1920,22 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
1920 hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); 1920 hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]);
1921 } 1921 }
1922 1922
1923 skb->ip_summed = card->options.checksum_type; 1923 switch (card->options.checksum_type) {
1924 if (card->options.checksum_type == HW_CHECKSUMMING) { 1924 case SW_CHECKSUMMING:
1925 skb->ip_summed = CHECKSUM_NONE;
1926 break;
1927 case NO_CHECKSUMMING:
1928 skb->ip_summed = CHECKSUM_UNNECESSARY;
1929 break;
1930 case HW_CHECKSUMMING:
1925 if ((hdr->hdr.l3.ext_flags & 1931 if ((hdr->hdr.l3.ext_flags &
1926 (QETH_HDR_EXT_CSUM_HDR_REQ | 1932 (QETH_HDR_EXT_CSUM_HDR_REQ |
1927 QETH_HDR_EXT_CSUM_TRANSP_REQ)) == 1933 QETH_HDR_EXT_CSUM_TRANSP_REQ)) ==
1928 (QETH_HDR_EXT_CSUM_HDR_REQ | 1934 (QETH_HDR_EXT_CSUM_HDR_REQ |
1929 QETH_HDR_EXT_CSUM_TRANSP_REQ)) 1935 QETH_HDR_EXT_CSUM_TRANSP_REQ))
1930 skb->ip_summed = CHECKSUM_UNNECESSARY; 1936 skb->ip_summed = CHECKSUM_UNNECESSARY;
1931 else 1937 else
1932 skb->ip_summed = SW_CHECKSUMMING; 1938 skb->ip_summed = CHECKSUM_NONE;
1933 } 1939 }
1934 1940
1935 return vlan_id; 1941 return vlan_id;
@@ -2543,9 +2549,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
2543 /* IPv4 */ 2549 /* IPv4 */
2544 hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); 2550 hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type);
2545 memset(hdr->hdr.l3.dest_addr, 0, 12); 2551 memset(hdr->hdr.l3.dest_addr, 0, 12);
2546 if ((skb->dst) && (skb->dst->neighbour)) { 2552 if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
2547 *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = 2553 *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
2548 *((u32 *) skb->dst->neighbour->primary_key); 2554 *((u32 *) skb_dst(skb)->neighbour->primary_key);
2549 } else { 2555 } else {
2550 /* fill in destination address used in ip header */ 2556 /* fill in destination address used in ip header */
2551 *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = 2557 *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
@@ -2556,9 +2562,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
2556 hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); 2562 hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type);
2557 if (card->info.type == QETH_CARD_TYPE_IQD) 2563 if (card->info.type == QETH_CARD_TYPE_IQD)
2558 hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; 2564 hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU;
2559 if ((skb->dst) && (skb->dst->neighbour)) { 2565 if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
2560 memcpy(hdr->hdr.l3.dest_addr, 2566 memcpy(hdr->hdr.l3.dest_addr,
2561 skb->dst->neighbour->primary_key, 16); 2567 skb_dst(skb)->neighbour->primary_key, 16);
2562 } else { 2568 } else {
2563 /* fill in destination address used in ip header */ 2569 /* fill in destination address used in ip header */
2564 memcpy(hdr->hdr.l3.dest_addr, 2570 memcpy(hdr->hdr.l3.dest_addr,
@@ -3006,6 +3012,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
3006 card->dev->features |= NETIF_F_HW_VLAN_TX | 3012 card->dev->features |= NETIF_F_HW_VLAN_TX |
3007 NETIF_F_HW_VLAN_RX | 3013 NETIF_F_HW_VLAN_RX |
3008 NETIF_F_HW_VLAN_FILTER; 3014 NETIF_F_HW_VLAN_FILTER;
3015 card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
3009 3016
3010 SET_NETDEV_DEV(card->dev, &card->gdev->dev); 3017 SET_NETDEV_DEV(card->dev, &card->gdev->dev);
3011 return register_netdev(card->dev); 3018 return register_netdev(card->dev);
@@ -3070,6 +3077,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
3070{ 3077{
3071 struct qeth_card *card = dev_get_drvdata(&cgdev->dev); 3078 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
3072 3079
3080 qeth_set_allowed_threads(card, 0, 1);
3073 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); 3081 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
3074 3082
3075 if (cgdev->state == CCWGROUP_ONLINE) { 3083 if (cgdev->state == CCWGROUP_ONLINE) {
@@ -3141,8 +3149,9 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
3141 dev_warn(&card->gdev->dev, 3149 dev_warn(&card->gdev->dev,
3142 "The LAN is offline\n"); 3150 "The LAN is offline\n");
3143 card->lan_online = 0; 3151 card->lan_online = 0;
3152 return 0;
3144 } 3153 }
3145 return rc; 3154 goto out_remove;
3146 } else 3155 } else
3147 card->lan_online = 1; 3156 card->lan_online = 1;
3148 qeth_set_large_send(card, card->options.large_send); 3157 qeth_set_large_send(card, card->options.large_send);
@@ -3274,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
3274 qeth_clear_qdio_buffers(card); 3283 qeth_clear_qdio_buffers(card);
3275} 3284}
3276 3285
3286static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
3287{
3288 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
3289
3290 if (card->dev)
3291 netif_device_detach(card->dev);
3292 qeth_set_allowed_threads(card, 0, 1);
3293 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
3294 if (gdev->state == CCWGROUP_OFFLINE)
3295 return 0;
3296 if (card->state == CARD_STATE_UP) {
3297 card->use_hard_stop = 1;
3298 __qeth_l3_set_offline(card->gdev, 1);
3299 } else
3300 __qeth_l3_set_offline(card->gdev, 0);
3301 return 0;
3302}
3303
3304static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
3305{
3306 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
3307 int rc = 0;
3308
3309 if (gdev->state == CCWGROUP_OFFLINE)
3310 goto out;
3311
3312 if (card->state == CARD_STATE_RECOVER) {
3313 rc = __qeth_l3_set_online(card->gdev, 1);
3314 if (rc) {
3315 if (card->dev) {
3316 rtnl_lock();
3317 dev_close(card->dev);
3318 rtnl_unlock();
3319 }
3320 }
3321 } else
3322 rc = __qeth_l3_set_online(card->gdev, 0);
3323out:
3324 qeth_set_allowed_threads(card, 0xffffffff, 0);
3325 if (card->dev)
3326 netif_device_attach(card->dev);
3327 if (rc)
3328 dev_warn(&card->gdev->dev, "The qeth device driver "
3329 "failed to recover an error on the device\n");
3330 return rc;
3331}
3332
3277struct ccwgroup_driver qeth_l3_ccwgroup_driver = { 3333struct ccwgroup_driver qeth_l3_ccwgroup_driver = {
3278 .probe = qeth_l3_probe_device, 3334 .probe = qeth_l3_probe_device,
3279 .remove = qeth_l3_remove_device, 3335 .remove = qeth_l3_remove_device,
3280 .set_online = qeth_l3_set_online, 3336 .set_online = qeth_l3_set_online,
3281 .set_offline = qeth_l3_set_offline, 3337 .set_offline = qeth_l3_set_offline,
3282 .shutdown = qeth_l3_shutdown, 3338 .shutdown = qeth_l3_shutdown,
3339 .freeze = qeth_l3_pm_suspend,
3340 .thaw = qeth_l3_pm_resume,
3341 .restore = qeth_l3_pm_resume,
3283}; 3342};
3284EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); 3343EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver);
3285 3344
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 164e090c2625..e76a320d373b 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * IUCV special message driver 2 * IUCV special message driver
3 * 3 *
4 * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation 4 * Copyright IBM Corp. 2003, 2009
5 *
5 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
@@ -40,6 +41,8 @@ MODULE_AUTHOR
40MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); 41MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
41 42
42static struct iucv_path *smsg_path; 43static struct iucv_path *smsg_path;
44/* dummy device used as trigger for PM functions */
45static struct device *smsg_dev;
43 46
44static DEFINE_SPINLOCK(smsg_list_lock); 47static DEFINE_SPINLOCK(smsg_list_lock);
45static LIST_HEAD(smsg_list); 48static LIST_HEAD(smsg_list);
@@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix,
132 kfree(cb); 135 kfree(cb);
133} 136}
134 137
138static int smsg_pm_freeze(struct device *dev)
139{
140#ifdef CONFIG_PM_DEBUG
141 printk(KERN_WARNING "smsg_pm_freeze\n");
142#endif
143 if (smsg_path)
144 iucv_path_sever(smsg_path, NULL);
145 return 0;
146}
147
148static int smsg_pm_restore_thaw(struct device *dev)
149{
150 int rc;
151
152#ifdef CONFIG_PM_DEBUG
153 printk(KERN_WARNING "smsg_pm_restore_thaw\n");
154#endif
155 if (smsg_path) {
156 memset(smsg_path, 0, sizeof(*smsg_path));
157 smsg_path->msglim = 255;
158 smsg_path->flags = 0;
159 rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ",
160 NULL, NULL, NULL);
161 printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc);
162 }
163 return 0;
164}
165
166static struct dev_pm_ops smsg_pm_ops = {
167 .freeze = smsg_pm_freeze,
168 .thaw = smsg_pm_restore_thaw,
169 .restore = smsg_pm_restore_thaw,
170};
171
135static struct device_driver smsg_driver = { 172static struct device_driver smsg_driver = {
173 .owner = THIS_MODULE,
136 .name = "SMSGIUCV", 174 .name = "SMSGIUCV",
137 .bus = &iucv_bus, 175 .bus = &iucv_bus,
176 .pm = &smsg_pm_ops,
138}; 177};
139 178
140static void __exit smsg_exit(void) 179static void __exit smsg_exit(void)
141{ 180{
142 cpcmd("SET SMSG IUCV", NULL, 0, NULL); 181 cpcmd("SET SMSG IUCV", NULL, 0, NULL);
182 device_unregister(smsg_dev);
143 iucv_unregister(&smsg_handler, 1); 183 iucv_unregister(&smsg_handler, 1);
144 driver_unregister(&smsg_driver); 184 driver_unregister(&smsg_driver);
145} 185}
@@ -166,12 +206,29 @@ static int __init smsg_init(void)
166 rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", 206 rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ",
167 NULL, NULL, NULL); 207 NULL, NULL, NULL);
168 if (rc) 208 if (rc)
169 goto out_free; 209 goto out_free_path;
210 smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
211 if (!smsg_dev) {
212 rc = -ENOMEM;
213 goto out_free_path;
214 }
215 dev_set_name(smsg_dev, "smsg_iucv");
216 smsg_dev->bus = &iucv_bus;
217 smsg_dev->parent = iucv_root;
218 smsg_dev->release = (void (*)(struct device *))kfree;
219 smsg_dev->driver = &smsg_driver;
220 rc = device_register(smsg_dev);
221 if (rc)
222 goto out_free_dev;
223
170 cpcmd("SET SMSG IUCV", NULL, 0, NULL); 224 cpcmd("SET SMSG IUCV", NULL, 0, NULL);
171 return 0; 225 return 0;
172 226
173out_free: 227out_free_dev:
228 kfree(smsg_dev);
229out_free_path:
174 iucv_path_free(smsg_path); 230 iucv_path_free(smsg_path);
231 smsg_path = NULL;
175out_register: 232out_register:
176 iucv_unregister(&smsg_handler, 1); 233 iucv_unregister(&smsg_handler, 1);
177out_driver: 234out_driver: