[S390] ccw_device_notify: improve return codes
Sebastian Ott [Fri, 26 Feb 2010 21:37:28 +0000 (22:37 +0100)]
Callers of ccw_device_notify could not distinguish between a driver
who has no notifier registered and a driver who doesn't want to keep
a device after a certain event. Change this by adding proper return
codes.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c

index 6aa2f06..c7b2b7b 100644 (file)
@@ -1338,7 +1338,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
                /* Not operational. */
                if (!cdev)
                        return IO_SCH_UNREG;
-               if (!ccw_device_notify(cdev, CIO_GONE))
+               if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
                        return IO_SCH_UNREG;
                return IO_SCH_ORPH_UNREG;
        }
@@ -1346,12 +1346,12 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
        if (!cdev)
                return IO_SCH_ATTACH;
        if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
-               if (!ccw_device_notify(cdev, CIO_GONE))
+               if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
                        return IO_SCH_UNREG_ATTACH;
                return IO_SCH_ORPH_ATTACH;
        }
        if ((sch->schib.pmcw.pam & sch->opm) == 0) {
-               if (!ccw_device_notify(cdev, CIO_NO_PATH))
+               if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
                        return IO_SCH_UNREG;
                return IO_SCH_DISC;
        }
@@ -1788,7 +1788,7 @@ out:
 static int resume_handle_boxed(struct ccw_device *cdev)
 {
        cdev->private->state = DEV_STATE_BOXED;
-       if (ccw_device_notify(cdev, CIO_BOXED))
+       if (ccw_device_notify(cdev, CIO_BOXED) == NOTIFY_OK)
                return 0;
        ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
        return -ENODEV;
@@ -1797,7 +1797,7 @@ static int resume_handle_boxed(struct ccw_device *cdev)
 static int resume_handle_disc(struct ccw_device *cdev)
 {
        cdev->private->state = DEV_STATE_DISCONNECTED;
-       if (ccw_device_notify(cdev, CIO_GONE))
+       if (ccw_device_notify(cdev, CIO_GONE) == NOTIFY_OK)
                return 0;
        ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
        return -ENODEV;
index ef60c8f..379de2d 100644 (file)
@@ -4,7 +4,7 @@
 #include <asm/ccwdev.h>
 #include <asm/atomic.h>
 #include <linux/wait.h>
-
+#include <linux/notifier.h>
 #include "io_sch.h"
 
 /*
index ae76065..2cb0186 100644 (file)
@@ -313,21 +313,43 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err)
        }
 }
 
+/**
+  * ccw_device_notify() - inform the device's driver about an event
+  * @cdev: device for which an event occured
+  * @event: event that occurred
+  *
+  * Returns:
+  *   -%EINVAL if the device is offline or has no driver.
+  *   -%EOPNOTSUPP if the device's driver has no notifier registered.
+  *   %NOTIFY_OK if the driver wants to keep the device.
+  *   %NOTIFY_BAD if the driver doesn't want to keep the device.
+  */
 int ccw_device_notify(struct ccw_device *cdev, int event)
 {
+       int ret = -EINVAL;
+
        if (!cdev->drv)
-               return 0;
+               goto out;
        if (!cdev->online)
-               return 0;
+               goto out;
        CIO_MSG_EVENT(2, "notify called for 0.%x.%04x, event=%d\n",
                      cdev->private->dev_id.ssid, cdev->private->dev_id.devno,
                      event);
-       return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
+       if (!cdev->drv->notify) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+       if (cdev->drv->notify(cdev, event))
+               ret = NOTIFY_OK;
+       else
+               ret = NOTIFY_BAD;
+out:
+       return ret;
 }
 
 static void ccw_device_oper_notify(struct ccw_device *cdev)
 {
-       if (ccw_device_notify(cdev, CIO_OPER)) {
+       if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) {
                /* Reenable channel measurements, if needed. */
                ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
                return;
@@ -361,14 +383,15 @@ ccw_device_done(struct ccw_device *cdev, int state)
        case DEV_STATE_BOXED:
                CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
                              cdev->private->dev_id.devno, sch->schid.sch_no);
-               if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
+               if (cdev->online &&
+                   ccw_device_notify(cdev, CIO_BOXED) != NOTIFY_OK)
                        ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
                cdev->private->flags.donotify = 0;
                break;
        case DEV_STATE_NOT_OPER:
                CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
                              cdev->private->dev_id.devno, sch->schid.sch_no);
-               if (!ccw_device_notify(cdev, CIO_GONE))
+               if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
                        ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
                else
                        ccw_device_set_disconnected(cdev);
@@ -378,7 +401,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
                CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
                              "%04x\n", cdev->private->dev_id.devno,
                              sch->schid.sch_no);
-               if (!ccw_device_notify(cdev, CIO_NO_PATH))
+               if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
                        ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
                else
                        ccw_device_set_disconnected(cdev);
@@ -586,7 +609,7 @@ ccw_device_offline(struct ccw_device *cdev)
 static void ccw_device_generic_notoper(struct ccw_device *cdev,
                                       enum dev_event dev_event)
 {
-       if (!ccw_device_notify(cdev, CIO_GONE))
+       if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
                ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
        else
                ccw_device_set_disconnected(cdev);