aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorEinar Lueck <elelueck@de.ibm.com>2009-10-14 18:54:59 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-18 02:57:24 -0400
commita1c1f5eab7d8c3b4f645df8ce2882ff4f578aa45 (patch)
tree9c153a26263abd2455ec11c424cb5a764759900a /drivers/s390
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>
Diffstat (limited to 'drivers/s390')
-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 c5b83874500c..db054ed1a8cc 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)
1530 struct net_device *dev; 1530 struct net_device *dev;
1531 struct ccw_device *cdev0; 1531 struct ccw_device *cdev0;
1532 struct ccw_device *cdev1; 1532 struct ccw_device *cdev1;
1533 struct channel *readc;
1534 struct channel *writec;
1533 int ret; 1535 int ret;
1536 int result;
1534 1537
1535 priv = dev_get_drvdata(&cgdev->dev); 1538 priv = dev_get_drvdata(&cgdev->dev);
1536 if (!priv) 1539 if (!priv) {
1537 return -ENODEV; 1540 result = -ENODEV;
1541 goto out_err_result;
1542 }
1538 1543
1539 cdev0 = cgdev->cdev[0]; 1544 cdev0 = cgdev->cdev[0];
1540 cdev1 = cgdev->cdev[1]; 1545 cdev1 = cgdev->cdev[1];
@@ -1545,31 +1550,40 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
1545 snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); 1550 snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev));
1546 1551
1547 ret = add_channel(cdev0, type, priv); 1552 ret = add_channel(cdev0, type, priv);
1548 if (ret) 1553 if (ret) {
1549 return ret; 1554 result = ret;
1555 goto out_err_result;
1556 }
1550 ret = add_channel(cdev1, type, priv); 1557 ret = add_channel(cdev1, type, priv);
1551 if (ret) 1558 if (ret) {
1552 return ret; 1559 result = ret;
1560 goto out_remove_channel1;
1561 }
1553 1562
1554 ret = ccw_device_set_online(cdev0); 1563 ret = ccw_device_set_online(cdev0);
1555 if (ret != 0) { 1564 if (ret != 0) {
1556 /* may be ok to fail now - can be done later */
1557 CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, 1565 CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
1558 "%s(%s) set_online rc=%d", 1566 "%s(%s) set_online rc=%d",
1559 CTCM_FUNTAIL, read_id, ret); 1567 CTCM_FUNTAIL, read_id, ret);
1568 result = -EIO;
1569 goto out_remove_channel2;
1560 } 1570 }
1561 1571
1562 ret = ccw_device_set_online(cdev1); 1572 ret = ccw_device_set_online(cdev1);
1563 if (ret != 0) { 1573 if (ret != 0) {
1564 /* may be ok to fail now - can be done later */
1565 CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, 1574 CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
1566 "%s(%s) set_online rc=%d", 1575 "%s(%s) set_online rc=%d",
1567 CTCM_FUNTAIL, write_id, ret); 1576 CTCM_FUNTAIL, write_id, ret);
1577
1578 result = -EIO;
1579 goto out_ccw1;
1568 } 1580 }
1569 1581
1570 dev = ctcm_init_netdevice(priv); 1582 dev = ctcm_init_netdevice(priv);
1571 if (dev == NULL) 1583 if (dev == NULL) {
1572 goto out; 1584 result = -ENODEV;
1585 goto out_ccw2;
1586 }
1573 1587
1574 for (direction = READ; direction <= WRITE; direction++) { 1588 for (direction = READ; direction <= WRITE; direction++) {
1575 priv->channel[direction] = 1589 priv->channel[direction] =
@@ -1587,12 +1601,14 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
1587 /* sysfs magic */ 1601 /* sysfs magic */
1588 SET_NETDEV_DEV(dev, &cgdev->dev); 1602 SET_NETDEV_DEV(dev, &cgdev->dev);
1589 1603
1590 if (register_netdev(dev)) 1604 if (register_netdev(dev)) {
1591 goto out_dev; 1605 result = -ENODEV;
1606 goto out_dev;
1607 }
1592 1608
1593 if (ctcm_add_attributes(&cgdev->dev)) { 1609 if (ctcm_add_attributes(&cgdev->dev)) {
1594 unregister_netdev(dev); 1610 result = -ENODEV;
1595 goto out_dev; 1611 goto out_unregister;
1596 } 1612 }
1597 1613
1598 strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); 1614 strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name));
@@ -1608,13 +1624,22 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
1608 priv->channel[WRITE]->id, priv->protocol); 1624 priv->channel[WRITE]->id, priv->protocol);
1609 1625
1610 return 0; 1626 return 0;
1627out_unregister:
1628 unregister_netdev(dev);
1611out_dev: 1629out_dev:
1612 ctcm_free_netdevice(dev); 1630 ctcm_free_netdevice(dev);
1613out: 1631out_ccw2:
1614 ccw_device_set_offline(cgdev->cdev[1]); 1632 ccw_device_set_offline(cgdev->cdev[1]);
1633out_ccw1:
1615 ccw_device_set_offline(cgdev->cdev[0]); 1634 ccw_device_set_offline(cgdev->cdev[0]);
1616 1635out_remove_channel2:
1617 return -ENODEV; 1636 readc = channel_get(type, read_id, READ);
1637 channel_remove(readc);
1638out_remove_channel1:
1639 writec = channel_get(type, write_id, WRITE);
1640 channel_remove(writec);
1641out_err_result:
1642 return result;
1618} 1643}
1619 1644
1620/** 1645/**