summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEinar Lueck <elelueck@de.ibm.com>2009-10-14 22:54:59 +0000
committerDavid S. Miller <davem@davemloft.net>2009-10-17 23:57:24 -0700
commita1c1f5eab7d8c3b4f645df8ce2882ff4f578aa45 (patch)
tree9c153a26263abd2455ec11c424cb5a764759900a
parentd816d4238245b019d6f86f58163c78f015bd94ed (diff)
ctcm rollback in case of errors
Group device now cleanly reacts to failures during channel start and implements a clean rollback. Signed-off-by: Einar Lueck <elelueck@de.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/s390/net/ctcm_main.c59
1 files changed, 42 insertions, 17 deletions
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index c5b83874500..db054ed1a8c 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -1530,11 +1530,16 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
struct net_device *dev;
struct ccw_device *cdev0;
struct ccw_device *cdev1;
+ struct channel *readc;
+ struct channel *writec;
int ret;
+ int result;
priv = dev_get_drvdata(&cgdev->dev);
- if (!priv)
- return -ENODEV;
+ if (!priv) {
+ result = -ENODEV;
+ goto out_err_result;
+ }
cdev0 = cgdev->cdev[0];
cdev1 = cgdev->cdev[1];
@@ -1545,31 +1550,40 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev));
ret = add_channel(cdev0, type, priv);
- if (ret)
- return ret;
+ if (ret) {
+ result = ret;
+ goto out_err_result;
+ }
ret = add_channel(cdev1, type, priv);
- if (ret)
- return ret;
+ if (ret) {
+ result = ret;
+ goto out_remove_channel1;
+ }
ret = ccw_device_set_online(cdev0);
if (ret != 0) {
- /* may be ok to fail now - can be done later */
CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
"%s(%s) set_online rc=%d",
CTCM_FUNTAIL, read_id, ret);
+ result = -EIO;
+ goto out_remove_channel2;
}
ret = ccw_device_set_online(cdev1);
if (ret != 0) {
- /* may be ok to fail now - can be done later */
CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
"%s(%s) set_online rc=%d",
CTCM_FUNTAIL, write_id, ret);
+
+ result = -EIO;
+ goto out_ccw1;
}
dev = ctcm_init_netdevice(priv);
- if (dev == NULL)
- goto out;
+ if (dev == NULL) {
+ result = -ENODEV;
+ goto out_ccw2;
+ }
for (direction = READ; direction <= WRITE; direction++) {
priv->channel[direction] =
@@ -1587,12 +1601,14 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
/* sysfs magic */
SET_NETDEV_DEV(dev, &cgdev->dev);
- if (register_netdev(dev))
- goto out_dev;
+ if (register_netdev(dev)) {
+ result = -ENODEV;
+ goto out_dev;
+ }
if (ctcm_add_attributes(&cgdev->dev)) {
- unregister_netdev(dev);
- goto out_dev;
+ result = -ENODEV;
+ goto out_unregister;
}
strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name));
@@ -1608,13 +1624,22 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
priv->channel[WRITE]->id, priv->protocol);
return 0;
+out_unregister:
+ unregister_netdev(dev);
out_dev:
ctcm_free_netdevice(dev);
-out:
+out_ccw2:
ccw_device_set_offline(cgdev->cdev[1]);
+out_ccw1:
ccw_device_set_offline(cgdev->cdev[0]);
-
- return -ENODEV;
+out_remove_channel2:
+ readc = channel_get(type, read_id, READ);
+ channel_remove(readc);
+out_remove_channel1:
+ writec = channel_get(type, write_id, WRITE);
+ channel_remove(writec);
+out_err_result:
+ return result;
}
/**