Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=90ab133603d066e850fc9ed297b6eb52f888dd25
Commit:     90ab133603d066e850fc9ed297b6eb52f888dd25
Parent:     808e48882316dd4a325cd1cc382516945edad77d
Author:     Peter Oberparleiter <[EMAIL PROTECTED]>
AuthorDate: Sat Jan 26 14:10:52 2008 +0100
Committer:  Martin Schwidefsky <[EMAIL PROTECTED]>
CommitDate: Sat Jan 26 14:11:06 2008 +0100

    [S390] cio: introduce timed recovery procedure
    
    Add a timed recovery procedure to reactivate ccw devices in cases
    where HW/VM events are not sufficient to allow for proper recovery
    of reappearing channel paths.
    
    Signed-off-by: Peter Oberparleiter <[EMAIL PROTECTED]>
    Signed-off-by: Martin Schwidefsky <[EMAIL PROTECTED]>
---
 drivers/s390/cio/device.c     |   63 +++++++++++++++++++++++++++++++++++++++++
 drivers/s390/cio/device.h     |    2 +
 drivers/s390/cio/device_fsm.c |    2 +
 3 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index f80d7f5..d35dc3f 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
+#include <linux/timer.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
@@ -30,6 +31,11 @@
 #include "ioasm.h"
 #include "io_sch.h"
 
+static struct timer_list recovery_timer;
+static spinlock_t recovery_lock;
+static int recovery_phase;
+static const unsigned long recovery_delay[] = { 3, 30, 300 };
+
 /******************* bus type handling ***********************/
 
 /* The Linux driver model distinguishes between a bus type and
@@ -142,6 +148,8 @@ struct workqueue_struct *ccw_device_notify_work;
 wait_queue_head_t ccw_device_init_wq;
 atomic_t ccw_device_init_count;
 
+static void recovery_func(unsigned long data);
+
 static int __init
 init_ccw_bus_type (void)
 {
@@ -149,6 +157,7 @@ init_ccw_bus_type (void)
 
        init_waitqueue_head(&ccw_device_init_wq);
        atomic_set(&ccw_device_init_count, 0);
+       setup_timer(&recovery_timer, recovery_func, 0);
 
        ccw_device_work = create_singlethread_workqueue("cio");
        if (!ccw_device_work)
@@ -1503,6 +1512,60 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
        return sch->schid;
 }
 
+static int recovery_check(struct device *dev, void *data)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       int *redo = data;
+
+       spin_lock_irq(cdev->ccwlock);
+       switch (cdev->private->state) {
+       case DEV_STATE_DISCONNECTED:
+               CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
+                             cdev->private->dev_id.ssid,
+                             cdev->private->dev_id.devno);
+               dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+               *redo = 1;
+               break;
+       case DEV_STATE_DISCONNECTED_SENSE_ID:
+               *redo = 1;
+               break;
+       }
+       spin_unlock_irq(cdev->ccwlock);
+
+       return 0;
+}
+
+static void recovery_func(unsigned long data)
+{
+       int redo = 0;
+
+       bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
+       if (redo) {
+               spin_lock_irq(&recovery_lock);
+               if (!timer_pending(&recovery_timer)) {
+                       if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
+                               recovery_phase++;
+                       mod_timer(&recovery_timer, jiffies +
+                                 recovery_delay[recovery_phase] * HZ);
+               }
+               spin_unlock_irq(&recovery_lock);
+       } else
+               CIO_MSG_EVENT(2, "recovery: end\n");
+}
+
+void ccw_device_schedule_recovery(void)
+{
+       unsigned long flags;
+
+       CIO_MSG_EVENT(2, "recovery: schedule\n");
+       spin_lock_irqsave(&recovery_lock, flags);
+       if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
+               recovery_phase = 0;
+               mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
+       }
+       spin_unlock_irqrestore(&recovery_lock, flags);
+}
+
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 87576fe..d40a2ff 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -88,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
 
+void ccw_device_schedule_recovery(void);
+
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
 void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 485741a..4b92c84 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -61,6 +61,8 @@ device_set_disconnected(struct subchannel *sch)
        ccw_device_set_timeout(cdev, 0);
        cdev->private->flags.fake_irb = 0;
        cdev->private->state = DEV_STATE_DISCONNECTED;
+       if (cdev->online)
+               ccw_device_schedule_recovery();
 }
 
 void device_set_intretry(struct subchannel *sch)
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to