Commit 39d324ae authored by Cornelia Huck's avatar Cornelia Huck Committed by Linus Torvalds

[PATCH] s390: irb faking.

Common i/o layer changes:
 - If a device driver tries to start I/O while the common I/O layer wants
   to start path verification, don't reject the I/O with -EBUSY (which
   might prompt the driver to retry the next tick) but seemingly accept
   the I/O and deliver a fake irb with deferred cc 1 after path
   verification has finished (prompting the driver to retry the I/O).
   This prevents the device driver from doing useless retries while cio
   is still busy with path verification.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d872210a
...@@ -703,6 +703,9 @@ __check_for_io_and_kill(struct subchannel *sch, int index) ...@@ -703,6 +703,9 @@ __check_for_io_and_kill(struct subchannel *sch, int index)
{ {
int cc; int cc;
if (!device_is_online(sch))
/* cio could be doing I/O. */
return 0;
cc = stsch(sch->irq, &sch->schib); cc = stsch(sch->irq, &sch->schib);
if (cc) if (cc)
return 0; return 0;
......
...@@ -84,6 +84,7 @@ struct ccw_device_private { ...@@ -84,6 +84,7 @@ struct ccw_device_private {
unsigned int doverify:1; /* delayed path verification */ unsigned int doverify:1; /* delayed path verification */
unsigned int donotify:1; /* call notify function */ unsigned int donotify:1; /* call notify function */
unsigned int recog_done:1; /* dev. recog. complete */ unsigned int recog_done:1; /* dev. recog. complete */
unsigned int fake_irb:1; /* deliver faked irb */
} __attribute__((packed)) flags; } __attribute__((packed)) flags;
unsigned long intparm; /* user interruption parameter */ unsigned long intparm; /* user interruption parameter */
struct qdio_irq *qdio_data; struct qdio_irq *qdio_data;
...@@ -136,6 +137,7 @@ void device_set_disconnected(struct subchannel *); ...@@ -136,6 +137,7 @@ void device_set_disconnected(struct subchannel *);
void device_trigger_reprobe(struct subchannel *); void device_trigger_reprobe(struct subchannel *);
/* Helper functions for vary on/off. */ /* Helper functions for vary on/off. */
int device_is_online(struct subchannel *);
void device_set_waiting(struct subchannel *); void device_set_waiting(struct subchannel *);
/* Machine check helper function. */ /* Machine check helper function. */
......
...@@ -23,6 +23,17 @@ ...@@ -23,6 +23,17 @@
#include "ioasm.h" #include "ioasm.h"
#include "qdio.h" #include "qdio.h"
int
device_is_online(struct subchannel *sch)
{
struct ccw_device *cdev;
if (!sch->dev.driver_data)
return 0;
cdev = sch->dev.driver_data;
return (cdev->private->state == DEV_STATE_ONLINE);
}
int int
device_is_disconnected(struct subchannel *sch) device_is_disconnected(struct subchannel *sch)
{ {
...@@ -44,6 +55,7 @@ device_set_disconnected(struct subchannel *sch) ...@@ -44,6 +55,7 @@ device_set_disconnected(struct subchannel *sch)
return; return;
cdev = sch->dev.driver_data; cdev = sch->dev.driver_data;
ccw_device_set_timeout(cdev, 0); ccw_device_set_timeout(cdev, 0);
cdev->private->flags.fake_irb = 0;
cdev->private->state = DEV_STATE_DISCONNECTED; cdev->private->state = DEV_STATE_DISCONNECTED;
} }
...@@ -474,6 +486,7 @@ ccw_device_nopath_notify(void *data) ...@@ -474,6 +486,7 @@ ccw_device_nopath_notify(void *data)
} else { } else {
cio_disable_subchannel(sch); cio_disable_subchannel(sch);
ccw_device_set_timeout(cdev, 0); ccw_device_set_timeout(cdev, 0);
cdev->private->flags.fake_irb = 0;
cdev->private->state = DEV_STATE_DISCONNECTED; cdev->private->state = DEV_STATE_DISCONNECTED;
wake_up(&cdev->private->wait_q); wake_up(&cdev->private->wait_q);
} }
...@@ -488,6 +501,21 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) ...@@ -488,6 +501,21 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
cdev->private->options.pgroup = 0; cdev->private->options.pgroup = 0;
case 0: case 0:
ccw_device_done(cdev, DEV_STATE_ONLINE); ccw_device_done(cdev, DEV_STATE_ONLINE);
/* Deliver fake irb to device driver, if needed. */
if (cdev->private->flags.fake_irb) {
memset(&cdev->private->irb, 0, sizeof(struct irb));
cdev->private->irb.scsw = (struct scsw) {
.cc = 1,
.fctl = SCSW_FCTL_START_FUNC,
.actl = SCSW_ACTL_START_PEND,
.stctl = SCSW_STCTL_STATUS_PEND,
};
cdev->private->flags.fake_irb = 0;
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
&cdev->private->irb);
memset(&cdev->private->irb, 0, sizeof(struct irb));
}
break; break;
case -ETIME: case -ETIME:
ccw_device_done(cdev, DEV_STATE_BOXED); ccw_device_done(cdev, DEV_STATE_BOXED);
...@@ -639,6 +667,7 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) ...@@ -639,6 +667,7 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
if (sch->driver->notify && if (sch->driver->notify &&
sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) { sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) {
ccw_device_set_timeout(cdev, 0); ccw_device_set_timeout(cdev, 0);
cdev->private->flags.fake_irb = 0;
cdev->private->state = DEV_STATE_DISCONNECTED; cdev->private->state = DEV_STATE_DISCONNECTED;
wake_up(&cdev->private->wait_q); wake_up(&cdev->private->wait_q);
return; return;
......
...@@ -81,6 +81,16 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, ...@@ -81,6 +81,16 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
return -ENODEV; return -ENODEV;
if (cdev->private->state == DEV_STATE_NOT_OPER) if (cdev->private->state == DEV_STATE_NOT_OPER)
return -ENODEV; return -ENODEV;
if (cdev->private->state == DEV_STATE_VERIFY) {
/* Remember to fake irb when finished. */
if (!cdev->private->flags.fake_irb) {
cdev->private->flags.fake_irb = 1;
cdev->private->intparm = intparm;
return 0;
} else
/* There's already a fake I/O around. */
return -EBUSY;
}
if (cdev->private->state != DEV_STATE_ONLINE || if (cdev->private->state != DEV_STATE_ONLINE ||
((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) && ((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
!(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) || !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
......
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