Commit d872210a authored by Cornelia Huck's avatar Cornelia Huck Committed by Linus Torvalds

[PATCH] s390: common i/o layer.

Common i/o layer changes:
 - Update scsw information before checking activity control bits in
   the offline processing.
 - Clear irb structure after cio initiated I/O completed.
 - Modify cdev private structure only while holding the lock.
 - Update scsw information before checking whether we can start path
   verification.
 - Only generate a notoper event if the device is not already in the
   not operation state, otherwise we end up with two unregister calls.
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 a9c09a69
/*
* drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call
* $Revision: 1.115 $
* $Revision: 1.118 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -423,12 +423,12 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
sch->schib.pmcw.pam &
sch->schib.pmcw.pom)
| chp_mask) & sch->opm;
spin_unlock_irq(&sch->lock);
if (!old_lpm && sch->lpm)
device_trigger_reprobe(sch);
else if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
spin_unlock_irq(&sch->lock);
put_device(&sch->dev);
if (fla_mask != 0)
break;
......@@ -717,10 +717,12 @@ static inline void
__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
{
int chp, old_lpm;
unsigned long flags;
if (!sch->ssd_info.valid)
return;
spin_lock_irqsave(&sch->lock, flags);
old_lpm = sch->lpm;
for (chp = 0; chp < 8; chp++) {
if (sch->ssd_info.chpid[chp] != chpid)
......@@ -751,6 +753,7 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
}
break;
}
spin_unlock_irqrestore(&sch->lock, flags);
}
static int
......
/*
* drivers/s390/cio/css.c
* driver for channel subsystem
* $Revision: 1.84 $
* $Revision: 1.85 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -180,6 +180,7 @@ css_evaluate_subchannel(int irq, int slow)
{
int event, ret, disc;
struct subchannel *sch;
unsigned long flags;
sch = get_subchannel_by_schid(irq);
disc = sch ? device_is_disconnected(sch) : 0;
......@@ -221,7 +222,9 @@ css_evaluate_subchannel(int irq, int slow)
* coming operational again. It won't do harm in real
* no path situations.
*/
spin_lock_irqsave(&sch->lock, flags);
device_trigger_reprobe(sch);
spin_unlock_irqrestore(&sch->lock, flags);
ret = 0;
break;
}
......@@ -262,14 +265,19 @@ css_evaluate_subchannel(int irq, int slow)
* We can't immediately deregister the disconnected
* device since it might block.
*/
spin_lock_irqsave(&sch->lock, flags);
device_trigger_reprobe(sch);
spin_unlock_irqrestore(&sch->lock, flags);
ret = 0;
}
break;
case CIO_OPER:
if (disc)
if (disc) {
spin_lock_irqsave(&sch->lock, flags);
/* Get device operational again. */
device_trigger_reprobe(sch);
spin_unlock_irqrestore(&sch->lock, flags);
}
ret = sch ? 0 : css_probe_device(irq);
break;
default:
......
/*
* drivers/s390/cio/device.c
* bus driver for ccw devices
* $Revision: 1.129 $
* $Revision: 1.131 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -293,6 +293,14 @@ ccw_device_set_offline(struct ccw_device *cdev)
cdev->online = 0;
spin_lock_irq(cdev->ccwlock);
ret = ccw_device_offline(cdev);
if (ret == -ENODEV) {
if (cdev->private->state != DEV_STATE_NOT_OPER) {
cdev->private->state = DEV_STATE_OFFLINE;
dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
}
spin_unlock_irq(cdev->ccwlock);
return ret;
}
spin_unlock_irq(cdev->ccwlock);
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
......
......@@ -560,6 +560,8 @@ ccw_device_offline(struct ccw_device *cdev)
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
if (stsch(sch->irq, &sch->schib) || !sch->schib.pmcw.dnv)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE) {
if (sch->schib.scsw.actl != 0)
return -EBUSY;
......@@ -668,6 +670,12 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
return;
}
sch = to_subchannel(cdev->dev.parent);
/*
* Since we might not just be coming from an interrupt from the
* subchannel we have to update the schib.
*/
stsch(sch->irq, &sch->schib);
if (sch->schib.scsw.actl != 0 ||
(cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
/*
......@@ -982,21 +990,17 @@ void
device_trigger_reprobe(struct subchannel *sch)
{
struct ccw_device *cdev;
unsigned long flags;
if (!sch->dev.driver_data)
return;
cdev = sch->dev.driver_data;
spin_lock_irqsave(&sch->lock, flags);
if (cdev->private->state != DEV_STATE_DISCONNECTED) {
spin_unlock_irqrestore(&sch->lock, flags);
if (cdev->private->state != DEV_STATE_DISCONNECTED)
return;
}
/* Update some values. */
if (stsch(sch->irq, &sch->schib)) {
spin_unlock_irqrestore(&sch->lock, flags);
if (stsch(sch->irq, &sch->schib))
return;
}
/*
* The pim, pam, pom values may not be accurate, but they are the best
* we have before performing device selection :/
......@@ -1014,7 +1018,6 @@ device_trigger_reprobe(struct subchannel *sch)
sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
/* We should also udate ssd info, but this has to wait. */
ccw_device_start_id(cdev, 0);
spin_unlock_irqrestore(&sch->lock, flags);
}
static void
......
......@@ -316,6 +316,7 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
return;
ret = ccw_device_check_sense_id(cdev);
memset(&cdev->private->irb, 0, sizeof(struct irb));
switch (ret) {
/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN or -EACCES */
case 0: /* Sense id succeeded. */
......
/*
* drivers/s390/cio/device_ops.c
*
* $Revision: 1.53 $
* $Revision: 1.55 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......
......@@ -156,7 +156,9 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
return;
sch = to_subchannel(cdev->dev.parent);
switch (__ccw_device_check_sense_pgid(cdev)) {
ret = __ccw_device_check_sense_pgid(cdev);
memset(&cdev->private->irb, 0, sizeof(struct irb));
switch (ret) {
/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
case 0: /* Sense Path Group ID successful. */
if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET)
......@@ -307,6 +309,7 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
{
struct subchannel *sch;
struct irb *irb;
int ret;
irb = (struct irb *) __LC_IRB;
/* Retry set pgid for cc=1. */
......@@ -319,7 +322,9 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
return;
sch = to_subchannel(cdev->dev.parent);
switch (__ccw_device_check_pgid(cdev)) {
ret = __ccw_device_check_pgid(cdev);
memset(&cdev->private->irb, 0, sizeof(struct irb));
switch (ret) {
/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
case 0:
/* Establish or Resign Path Group done. Update vpm. */
......@@ -405,6 +410,7 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
return;
sch = to_subchannel(cdev->dev.parent);
ret = __ccw_device_check_pgid(cdev);
memset(&cdev->private->irb, 0, sizeof(struct irb));
switch (ret) {
/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
case 0: /* disband successful. */
......
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