aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2010-02-26 16:37:29 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-02-26 16:37:30 -0500
commit0d01bb89220490763d89571d27e7ee3f13f9b372 (patch)
tree15d92ad8fda6e636c260f20f6ef094a53935ac26 /drivers/s390
parent76e6fb4b86446e4605379b99ad3dd3f96bb1696f (diff)
[S390] cio: trigger subchannel event at resume time
ccw_device_pm_restore: trigger subchannel event to better handle changes to the subchannel device. Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/css.c2
-rw-r--r--drivers/s390/cio/css.h1
-rw-r--r--drivers/s390/cio/device.c111
3 files changed, 63 insertions, 51 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 169a27723c4f..2769da54f2b9 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -1020,7 +1020,7 @@ static int css_settle(struct device_driver *drv, void *unused)
1020 return 0; 1020 return 0;
1021} 1021}
1022 1022
1023static inline int css_complete_work(void) 1023int css_complete_work(void)
1024{ 1024{
1025 int ret; 1025 int ret;
1026 1026
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 325d813bb8e0..7e37886de231 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -146,6 +146,7 @@ extern struct channel_subsystem *channel_subsystems[];
146/* Helper functions to build lists for the slow path. */ 146/* Helper functions to build lists for the slow path. */
147void css_schedule_eval(struct subchannel_id schid); 147void css_schedule_eval(struct subchannel_id schid);
148void css_schedule_eval_all(void); 148void css_schedule_eval_all(void);
149int css_complete_work(void);
149 150
150int sch_is_pseudo_sch(struct subchannel *); 151int sch_is_pseudo_sch(struct subchannel *);
151struct schib; 152struct schib;
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index c7b2b7b26b8b..c6abb75c4615 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1400,6 +1400,12 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
1400 rc = 0; 1400 rc = 0;
1401 goto out_unlock; 1401 goto out_unlock;
1402 case IO_SCH_VERIFY: 1402 case IO_SCH_VERIFY:
1403 if (cdev->private->flags.resuming == 1) {
1404 if (cio_enable_subchannel(sch, (u32)(addr_t)sch)) {
1405 ccw_device_set_notoper(cdev);
1406 break;
1407 }
1408 }
1403 /* Trigger path verification. */ 1409 /* Trigger path verification. */
1404 io_subchannel_verify(sch); 1410 io_subchannel_verify(sch);
1405 rc = 0; 1411 rc = 0;
@@ -1438,7 +1444,8 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
1438 break; 1444 break;
1439 case IO_SCH_UNREG_ATTACH: 1445 case IO_SCH_UNREG_ATTACH:
1440 /* Unregister ccw device. */ 1446 /* Unregister ccw device. */
1441 ccw_device_unregister(cdev); 1447 if (!cdev->private->flags.resuming)
1448 ccw_device_unregister(cdev);
1442 break; 1449 break;
1443 default: 1450 default:
1444 break; 1451 break;
@@ -1447,7 +1454,8 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
1447 switch (action) { 1454 switch (action) {
1448 case IO_SCH_ORPH_UNREG: 1455 case IO_SCH_ORPH_UNREG:
1449 case IO_SCH_UNREG: 1456 case IO_SCH_UNREG:
1450 css_sch_device_unregister(sch); 1457 if (!cdev || !cdev->private->flags.resuming)
1458 css_sch_device_unregister(sch);
1451 break; 1459 break;
1452 case IO_SCH_ORPH_ATTACH: 1460 case IO_SCH_ORPH_ATTACH:
1453 case IO_SCH_UNREG_ATTACH: 1461 case IO_SCH_UNREG_ATTACH:
@@ -1769,20 +1777,36 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
1769{ 1777{
1770 struct subchannel *sch = to_subchannel(cdev->dev.parent); 1778 struct subchannel *sch = to_subchannel(cdev->dev.parent);
1771 1779
1772 if (cio_is_console(sch->schid)) 1780 spin_lock_irq(sch->lock);
1773 goto out; 1781 if (cio_is_console(sch->schid)) {
1782 cio_enable_subchannel(sch, (u32)(addr_t)sch);
1783 goto out_unlock;
1784 }
1774 /* 1785 /*
1775 * While we were sleeping, devices may have gone or become 1786 * While we were sleeping, devices may have gone or become
1776 * available again. Kick re-detection. 1787 * available again. Kick re-detection.
1777 */ 1788 */
1778 spin_lock_irq(sch->lock);
1779 cdev->private->flags.resuming = 1; 1789 cdev->private->flags.resuming = 1;
1790 css_schedule_eval(sch->schid);
1791 spin_unlock_irq(sch->lock);
1792 css_complete_work();
1793
1794 /* cdev may have been moved to a different subchannel. */
1795 sch = to_subchannel(cdev->dev.parent);
1796 spin_lock_irq(sch->lock);
1797 if (cdev->private->state != DEV_STATE_ONLINE &&
1798 cdev->private->state != DEV_STATE_OFFLINE)
1799 goto out_unlock;
1800
1780 ccw_device_recognition(cdev); 1801 ccw_device_recognition(cdev);
1781 spin_unlock_irq(sch->lock); 1802 spin_unlock_irq(sch->lock);
1782 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || 1803 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
1783 cdev->private->state == DEV_STATE_DISCONNECTED); 1804 cdev->private->state == DEV_STATE_DISCONNECTED);
1784out: 1805 spin_lock_irq(sch->lock);
1806
1807out_unlock:
1785 cdev->private->flags.resuming = 0; 1808 cdev->private->flags.resuming = 0;
1809 spin_unlock_irq(sch->lock);
1786} 1810}
1787 1811
1788static int resume_handle_boxed(struct ccw_device *cdev) 1812static int resume_handle_boxed(struct ccw_device *cdev)
@@ -1806,40 +1830,31 @@ static int resume_handle_disc(struct ccw_device *cdev)
1806static int ccw_device_pm_restore(struct device *dev) 1830static int ccw_device_pm_restore(struct device *dev)
1807{ 1831{
1808 struct ccw_device *cdev = to_ccwdev(dev); 1832 struct ccw_device *cdev = to_ccwdev(dev);
1809 struct subchannel *sch = to_subchannel(cdev->dev.parent); 1833 struct subchannel *sch;
1810 int ret = 0, cm_enabled; 1834 int ret = 0;
1811 1835
1812 __ccw_device_pm_restore(cdev); 1836 __ccw_device_pm_restore(cdev);
1837 sch = to_subchannel(cdev->dev.parent);
1813 spin_lock_irq(sch->lock); 1838 spin_lock_irq(sch->lock);
1814 if (cio_is_console(sch->schid)) { 1839 if (cio_is_console(sch->schid))
1815 cio_enable_subchannel(sch, (u32)(addr_t)sch);
1816 spin_unlock_irq(sch->lock);
1817 goto out_restore; 1840 goto out_restore;
1818 } 1841
1819 cdev->private->flags.donotify = 0;
1820 /* check recognition results */ 1842 /* check recognition results */
1821 switch (cdev->private->state) { 1843 switch (cdev->private->state) {
1822 case DEV_STATE_OFFLINE: 1844 case DEV_STATE_OFFLINE:
1845 case DEV_STATE_ONLINE:
1846 cdev->private->flags.donotify = 0;
1823 break; 1847 break;
1824 case DEV_STATE_BOXED: 1848 case DEV_STATE_BOXED:
1825 ret = resume_handle_boxed(cdev); 1849 ret = resume_handle_boxed(cdev);
1826 spin_unlock_irq(sch->lock);
1827 if (ret) 1850 if (ret)
1828 goto out; 1851 goto out_unlock;
1829 goto out_restore; 1852 goto out_restore;
1830 case DEV_STATE_DISCONNECTED:
1831 goto out_disc_unlock;
1832 default: 1853 default:
1833 goto out_unreg_unlock; 1854 ret = resume_handle_disc(cdev);
1834 } 1855 if (ret)
1835 /* check if the device id has changed */ 1856 goto out_unlock;
1836 if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { 1857 goto out_restore;
1837 CIO_MSG_EVENT(0, "resume: sch 0.%x.%04x: failed (devno "
1838 "changed from %04x to %04x)\n",
1839 sch->schid.ssid, sch->schid.sch_no,
1840 cdev->private->dev_id.devno,
1841 sch->schib.pmcw.dev);
1842 goto out_unreg_unlock;
1843 } 1858 }
1844 /* check if the device type has changed */ 1859 /* check if the device type has changed */
1845 if (!ccw_device_test_sense_data(cdev)) { 1860 if (!ccw_device_test_sense_data(cdev)) {
@@ -1848,24 +1863,30 @@ static int ccw_device_pm_restore(struct device *dev)
1848 ret = -ENODEV; 1863 ret = -ENODEV;
1849 goto out_unlock; 1864 goto out_unlock;
1850 } 1865 }
1851 if (!cdev->online) { 1866 if (!cdev->online)
1852 ret = 0;
1853 goto out_unlock; 1867 goto out_unlock;
1854 }
1855 ret = ccw_device_online(cdev);
1856 if (ret)
1857 goto out_disc_unlock;
1858 1868
1859 cm_enabled = cdev->private->cmb != NULL; 1869 if (ccw_device_online(cdev)) {
1870 ret = resume_handle_disc(cdev);
1871 if (ret)
1872 goto out_unlock;
1873 goto out_restore;
1874 }
1860 spin_unlock_irq(sch->lock); 1875 spin_unlock_irq(sch->lock);
1861
1862 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); 1876 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
1863 if (cdev->private->state != DEV_STATE_ONLINE) { 1877 spin_lock_irq(sch->lock);
1864 spin_lock_irq(sch->lock); 1878
1865 goto out_disc_unlock; 1879 if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_BAD) {
1880 ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
1881 ret = -ENODEV;
1882 goto out_unlock;
1866 } 1883 }
1867 if (cm_enabled) { 1884
1885 /* reenable cmf, if needed */
1886 if (cdev->private->cmb) {
1887 spin_unlock_irq(sch->lock);
1868 ret = ccw_set_cmf(cdev, 1); 1888 ret = ccw_set_cmf(cdev, 1);
1889 spin_lock_irq(sch->lock);
1869 if (ret) { 1890 if (ret) {
1870 CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed " 1891 CIO_MSG_EVENT(2, "resume: cdev 0.%x.%04x: cmf failed "
1871 "(rc=%d)\n", cdev->private->dev_id.ssid, 1892 "(rc=%d)\n", cdev->private->dev_id.ssid,
@@ -1875,21 +1896,11 @@ static int ccw_device_pm_restore(struct device *dev)
1875 } 1896 }
1876 1897
1877out_restore: 1898out_restore:
1899 spin_unlock_irq(sch->lock);
1878 if (cdev->online && cdev->drv && cdev->drv->restore) 1900 if (cdev->online && cdev->drv && cdev->drv->restore)
1879 ret = cdev->drv->restore(cdev); 1901 ret = cdev->drv->restore(cdev);
1880out:
1881 return ret; 1902 return ret;
1882 1903
1883out_disc_unlock:
1884 ret = resume_handle_disc(cdev);
1885 spin_unlock_irq(sch->lock);
1886 if (ret)
1887 return ret;
1888 goto out_restore;
1889
1890out_unreg_unlock:
1891 ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
1892 ret = -ENODEV;
1893out_unlock: 1904out_unlock:
1894 spin_unlock_irq(sch->lock); 1905 spin_unlock_irq(sch->lock);
1895 return ret; 1906 return ret;