[S390] cio: Use path verification for last path gone after vary off.
authorCornelia Huck <cornelia.huck@de.ibm.com>
Mon, 4 Dec 2006 14:41:01 +0000 (15:41 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 4 Dec 2006 14:41:01 +0000 (15:41 +0100)
If the last path to a device is gone after a chpid has been varied
off, putting it on the slow queue doesn't prevent a device driver
from still attempting to use it (it may stay on the slow queue for a
long time). Instead, trigger a verify event which will prevent I/O
attempts from the device driver immediately.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/chsc.c
drivers/s390/cio/css.h
drivers/s390/cio/device_fsm.c

index 9d92540bd99e8c7cf84690470efa9d108df72f3e..11900de94cb301418a6df3e2c078aab678e8cf32 100644 (file)
@@ -744,20 +744,22 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
                                device_trigger_reprobe(sch);
                        else if (sch->driver && sch->driver->verify)
                                sch->driver->verify(&sch->dev);
-               } else {
-                       sch->opm &= ~(0x80 >> chp);
-                       sch->lpm &= ~(0x80 >> chp);
-                       if (check_for_io_on_path(sch, chp))
-                               /* Path verification is done after killing. */
-                               device_kill_io(sch);
-                       else if (!sch->lpm) {
+                       break;
+               }
+               sch->opm &= ~(0x80 >> chp);
+               sch->lpm &= ~(0x80 >> chp);
+               if (check_for_io_on_path(sch, chp))
+                       /* Path verification is done after killing. */
+                       device_kill_io(sch);
+               else if (!sch->lpm) {
+                       if (device_trigger_verify(sch) != 0) {
                                if (css_enqueue_subchannel_slow(sch->schid)) {
                                        css_clear_subchannel_slow_list();
                                        need_rescan = 1;
                                }
-                       } else if (sch->driver && sch->driver->verify)
-                               sch->driver->verify(&sch->dev);
-               }
+                       }
+               } else if (sch->driver && sch->driver->verify)
+                       sch->driver->verify(&sch->dev);
                break;
        }
        spin_unlock_irqrestore(&sch->lock, flags);
index 4c2ff83362887aafe64fea2a5ebf6137b8456b9a..da73453fa54b7df5c27a611f8fc0ccc8e0d04f30 100644 (file)
@@ -171,6 +171,7 @@ void device_trigger_reprobe(struct subchannel *);
 /* Helper functions for vary on/off. */
 int device_is_online(struct subchannel *);
 void device_kill_io(struct subchannel *);
+int device_trigger_verify(struct subchannel *sch);
 
 /* Machine check helper function. */
 void device_kill_pending_timer(struct subchannel *);
index de3d0857db9fb83b3526a5d0557876d35dc2b154..7665000e8dfe047de5cadb5d2076420d4909b36c 100644 (file)
@@ -59,6 +59,17 @@ device_set_disconnected(struct subchannel *sch)
        cdev->private->state = DEV_STATE_DISCONNECTED;
 }
 
+int device_trigger_verify(struct subchannel *sch)
+{
+       struct ccw_device *cdev;
+
+       cdev = sch->dev.driver_data;
+       if (!cdev || !cdev->online)
+               return -EINVAL;
+       dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+       return 0;
+}
+
 /*
  * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
  */