diff options
| author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2010-02-26 16:37:29 -0500 |
|---|---|---|
| committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-02-26 16:37:30 -0500 |
| commit | 0d01bb89220490763d89571d27e7ee3f13f9b372 (patch) | |
| tree | 15d92ad8fda6e636c260f20f6ef094a53935ac26 | |
| parent | 76e6fb4b86446e4605379b99ad3dd3f96bb1696f (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>
| -rw-r--r-- | drivers/s390/cio/css.c | 2 | ||||
| -rw-r--r-- | drivers/s390/cio/css.h | 1 | ||||
| -rw-r--r-- | drivers/s390/cio/device.c | 111 |
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 | ||
| 1023 | static inline int css_complete_work(void) | 1023 | int 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. */ |
| 147 | void css_schedule_eval(struct subchannel_id schid); | 147 | void css_schedule_eval(struct subchannel_id schid); |
| 148 | void css_schedule_eval_all(void); | 148 | void css_schedule_eval_all(void); |
| 149 | int css_complete_work(void); | ||
| 149 | 150 | ||
| 150 | int sch_is_pseudo_sch(struct subchannel *); | 151 | int sch_is_pseudo_sch(struct subchannel *); |
| 151 | struct schib; | 152 | struct 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); |
| 1784 | out: | 1805 | spin_lock_irq(sch->lock); |
| 1806 | |||
| 1807 | out_unlock: | ||
| 1785 | cdev->private->flags.resuming = 0; | 1808 | cdev->private->flags.resuming = 0; |
| 1809 | spin_unlock_irq(sch->lock); | ||
| 1786 | } | 1810 | } |
| 1787 | 1811 | ||
| 1788 | static int resume_handle_boxed(struct ccw_device *cdev) | 1812 | static int resume_handle_boxed(struct ccw_device *cdev) |
| @@ -1806,40 +1830,31 @@ static int resume_handle_disc(struct ccw_device *cdev) | |||
| 1806 | static int ccw_device_pm_restore(struct device *dev) | 1830 | static 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 | ||
| 1877 | out_restore: | 1898 | out_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); |
| 1880 | out: | ||
| 1881 | return ret; | 1902 | return ret; |
| 1882 | 1903 | ||
| 1883 | out_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 | |||
| 1890 | out_unreg_unlock: | ||
| 1891 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL); | ||
| 1892 | ret = -ENODEV; | ||
| 1893 | out_unlock: | 1904 | out_unlock: |
| 1894 | spin_unlock_irq(sch->lock); | 1905 | spin_unlock_irq(sch->lock); |
| 1895 | return ret; | 1906 | return ret; |
