diff options
author | Einar Lueck <elelueck@de.ibm.com> | 2009-10-14 18:54:59 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-18 02:57:24 -0400 |
commit | a1c1f5eab7d8c3b4f645df8ce2882ff4f578aa45 (patch) | |
tree | 9c153a26263abd2455ec11c424cb5a764759900a /drivers/s390 | |
parent | d816d4238245b019d6f86f58163c78f015bd94ed (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.c | 59 |
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; |
1627 | out_unregister: | ||
1628 | unregister_netdev(dev); | ||
1611 | out_dev: | 1629 | out_dev: |
1612 | ctcm_free_netdevice(dev); | 1630 | ctcm_free_netdevice(dev); |
1613 | out: | 1631 | out_ccw2: |
1614 | ccw_device_set_offline(cgdev->cdev[1]); | 1632 | ccw_device_set_offline(cgdev->cdev[1]); |
1633 | out_ccw1: | ||
1615 | ccw_device_set_offline(cgdev->cdev[0]); | 1634 | ccw_device_set_offline(cgdev->cdev[0]); |
1616 | 1635 | out_remove_channel2: | |
1617 | return -ENODEV; | 1636 | readc = channel_get(type, read_id, READ); |
1637 | channel_remove(readc); | ||
1638 | out_remove_channel1: | ||
1639 | writec = channel_get(type, write_id, WRITE); | ||
1640 | channel_remove(writec); | ||
1641 | out_err_result: | ||
1642 | return result; | ||
1618 | } | 1643 | } |
1619 | 1644 | ||
1620 | /** | 1645 | /** |