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