From: Cornelia Huck 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: Martin Schwidefsky Signed-off-by: Andrew Morton --- 25-akpm/drivers/s390/cio/chsc.c | 7 +++++-- 25-akpm/drivers/s390/cio/css.c | 12 ++++++++++-- 25-akpm/drivers/s390/cio/device.c | 10 +++++++++- 25-akpm/drivers/s390/cio/device_fsm.c | 21 ++++++++++++--------- 25-akpm/drivers/s390/cio/device_id.c | 1 + 25-akpm/drivers/s390/cio/device_ops.c | 2 +- 25-akpm/drivers/s390/cio/device_pgid.c | 10 ++++++++-- 7 files changed, 46 insertions(+), 17 deletions(-) diff -puN drivers/s390/cio/chsc.c~s390-common-i-o-layer drivers/s390/cio/chsc.c --- 25/drivers/s390/cio/chsc.c~s390-common-i-o-layer 2005-03-02 17:55:21.000000000 -0800 +++ 25-akpm/drivers/s390/cio/chsc.c 2005-03-02 17:55:21.000000000 -0800 @@ -1,7 +1,7 @@ /* * 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 fl 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 subc } break; } + spin_unlock_irqrestore(&sch->lock, flags); } static int diff -puN drivers/s390/cio/css.c~s390-common-i-o-layer drivers/s390/cio/css.c --- 25/drivers/s390/cio/css.c~s390-common-i-o-layer 2005-03-02 17:55:21.000000000 -0800 +++ 25-akpm/drivers/s390/cio/css.c 2005-03-02 17:55:21.000000000 -0800 @@ -1,7 +1,7 @@ /* * 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 slo { 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 slo * 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 slo * 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: diff -puN drivers/s390/cio/device.c~s390-common-i-o-layer drivers/s390/cio/device.c --- 25/drivers/s390/cio/device.c~s390-common-i-o-layer 2005-03-02 17:55:21.000000000 -0800 +++ 25-akpm/drivers/s390/cio/device.c 2005-03-02 17:55:21.000000000 -0800 @@ -1,7 +1,7 @@ /* * 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->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)); diff -puN drivers/s390/cio/device_fsm.c~s390-common-i-o-layer drivers/s390/cio/device_fsm.c --- 25/drivers/s390/cio/device_fsm.c~s390-common-i-o-layer 2005-03-02 17:55:21.000000000 -0800 +++ 25-akpm/drivers/s390/cio/device_fsm.c 2005-03-02 17:55:21.000000000 -0800 @@ -560,6 +560,8 @@ ccw_device_offline(struct ccw_device *cd 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_devi 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->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 diff -puN drivers/s390/cio/device_id.c~s390-common-i-o-layer drivers/s390/cio/device_id.c --- 25/drivers/s390/cio/device_id.c~s390-common-i-o-layer 2005-03-02 17:55:21.000000000 -0800 +++ 25-akpm/drivers/s390/cio/device_id.c 2005-03-02 17:55:21.000000000 -0800 @@ -316,6 +316,7 @@ ccw_device_sense_id_irq(struct ccw_devic 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. */ diff -puN drivers/s390/cio/device_ops.c~s390-common-i-o-layer drivers/s390/cio/device_ops.c --- 25/drivers/s390/cio/device_ops.c~s390-common-i-o-layer 2005-03-02 17:55:21.000000000 -0800 +++ 25-akpm/drivers/s390/cio/device_ops.c 2005-03-02 17:55:21.000000000 -0800 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/device_ops.c * - * $Revision: 1.53 $ + * $Revision: 1.55 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation diff -puN drivers/s390/cio/device_pgid.c~s390-common-i-o-layer drivers/s390/cio/device_pgid.c --- 25/drivers/s390/cio/device_pgid.c~s390-common-i-o-layer 2005-03-02 17:55:21.000000000 -0800 +++ 25-akpm/drivers/s390/cio/device_pgid.c 2005-03-02 17:55:21.000000000 -0800 @@ -156,7 +156,9 @@ ccw_device_sense_pgid_irq(struct ccw_dev 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 { 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 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 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. */ _