Commit 76e6fb4b authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky

[S390] ccw_device_notify: improve return codes

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: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent b4c70721
...@@ -1338,7 +1338,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch) ...@@ -1338,7 +1338,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
/* Not operational. */ /* Not operational. */
if (!cdev) if (!cdev)
return IO_SCH_UNREG; 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_UNREG;
return IO_SCH_ORPH_UNREG; return IO_SCH_ORPH_UNREG;
} }
...@@ -1346,12 +1346,12 @@ static enum io_sch_action sch_get_action(struct subchannel *sch) ...@@ -1346,12 +1346,12 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
if (!cdev) if (!cdev)
return IO_SCH_ATTACH; return IO_SCH_ATTACH;
if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { 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_UNREG_ATTACH;
return IO_SCH_ORPH_ATTACH; return IO_SCH_ORPH_ATTACH;
} }
if ((sch->schib.pmcw.pam & sch->opm) == 0) { 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_UNREG;
return IO_SCH_DISC; return IO_SCH_DISC;
} }
...@@ -1788,7 +1788,7 @@ out: ...@@ -1788,7 +1788,7 @@ out:
static int resume_handle_boxed(struct ccw_device *cdev) static int resume_handle_boxed(struct ccw_device *cdev)
{ {
cdev->private->state = DEV_STATE_BOXED; cdev->private->state = DEV_STATE_BOXED;
if (ccw_device_notify(cdev, CIO_BOXED)) if (ccw_device_notify(cdev, CIO_BOXED) == NOTIFY_OK)
return 0; return 0;
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
return -ENODEV; return -ENODEV;
...@@ -1797,7 +1797,7 @@ static int resume_handle_boxed(struct ccw_device *cdev) ...@@ -1797,7 +1797,7 @@ static int resume_handle_boxed(struct ccw_device *cdev)
static int resume_handle_disc(struct ccw_device *cdev) static int resume_handle_disc(struct ccw_device *cdev)
{ {
cdev->private->state = DEV_STATE_DISCONNECTED; cdev->private->state = DEV_STATE_DISCONNECTED;
if (ccw_device_notify(cdev, CIO_GONE)) if (ccw_device_notify(cdev, CIO_GONE) == NOTIFY_OK)
return 0; return 0;
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
return -ENODEV; return -ENODEV;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/notifier.h>
#include "io_sch.h" #include "io_sch.h"
/* /*
......
...@@ -313,21 +313,43 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err) ...@@ -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 ccw_device_notify(struct ccw_device *cdev, int event)
{ {
int ret = -EINVAL;
if (!cdev->drv) if (!cdev->drv)
return 0; goto out;
if (!cdev->online) if (!cdev->online)
return 0; goto out;
CIO_MSG_EVENT(2, "notify called for 0.%x.%04x, event=%d\n", CIO_MSG_EVENT(2, "notify called for 0.%x.%04x, event=%d\n",
cdev->private->dev_id.ssid, cdev->private->dev_id.devno, cdev->private->dev_id.ssid, cdev->private->dev_id.devno,
event); 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) 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. */ /* Reenable channel measurements, if needed. */
ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF); ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
return; return;
...@@ -361,14 +383,15 @@ ccw_device_done(struct ccw_device *cdev, int state) ...@@ -361,14 +383,15 @@ ccw_device_done(struct ccw_device *cdev, int state)
case DEV_STATE_BOXED: case DEV_STATE_BOXED:
CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n", CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no); 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); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
cdev->private->flags.donotify = 0; cdev->private->flags.donotify = 0;
break; break;
case DEV_STATE_NOT_OPER: case DEV_STATE_NOT_OPER:
CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n", CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no); 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); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else else
ccw_device_set_disconnected(cdev); ccw_device_set_disconnected(cdev);
...@@ -378,7 +401,7 @@ ccw_device_done(struct ccw_device *cdev, int state) ...@@ -378,7 +401,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
"%04x\n", cdev->private->dev_id.devno, "%04x\n", cdev->private->dev_id.devno,
sch->schid.sch_no); 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); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else else
ccw_device_set_disconnected(cdev); ccw_device_set_disconnected(cdev);
...@@ -586,7 +609,7 @@ ccw_device_offline(struct ccw_device *cdev) ...@@ -586,7 +609,7 @@ ccw_device_offline(struct ccw_device *cdev)
static void ccw_device_generic_notoper(struct ccw_device *cdev, static void ccw_device_generic_notoper(struct ccw_device *cdev,
enum dev_event dev_event) 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); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
else else
ccw_device_set_disconnected(cdev); ccw_device_set_disconnected(cdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment