Commit 387b734f authored by Stefan Bader's avatar Stefan Bader Committed by Martin Schwidefsky

[S390] cio: Re-start path verification after aborting internal I/O.

Path verification triggered by changes to the available CHPIDs will be
interrupted by another change but not re-started. This results in an
invalid path mask.
To solve this make sure to completely re-start path verification when
changing the available paths.
Signed-off-by: default avatarStefan Bader <shbader@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent cfbe9bb2
...@@ -178,6 +178,38 @@ css_get_ssd_info(struct subchannel *sch) ...@@ -178,6 +178,38 @@ css_get_ssd_info(struct subchannel *sch)
return ret; return ret;
} }
static int check_for_io_on_path(struct subchannel *sch, int mask)
{
int cc;
cc = stsch(sch->schid, &sch->schib);
if (cc)
return 0;
if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask)
return 1;
return 0;
}
static void terminate_internal_io(struct subchannel *sch)
{
if (cio_clear(sch)) {
/* Recheck device in case clear failed. */
sch->lpm = 0;
if (device_trigger_verify(sch) != 0) {
if(css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();
need_rescan = 1;
}
}
return;
}
/* Request retry of internal operation. */
device_set_intretry(sch);
/* Call handler. */
if (sch->driver && sch->driver->termination)
sch->driver->termination(&sch->dev);
}
static int static int
s390_subchannel_remove_chpid(struct device *dev, void *data) s390_subchannel_remove_chpid(struct device *dev, void *data)
{ {
...@@ -208,37 +240,33 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) ...@@ -208,37 +240,33 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
if (sch->schib.pmcw.pim == 0x80) if (sch->schib.pmcw.pim == 0x80)
goto out_unreg; goto out_unreg;
if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) && if (check_for_io_on_path(sch, mask)) {
(sch->schib.scsw.actl & SCSW_ACTL_SCHACT) && if (device_is_online(sch))
(sch->schib.pmcw.lpum == mask)) { device_kill_io(sch);
int cc; else {
terminate_internal_io(sch);
cc = cio_clear(sch); /* Re-start path verification. */
if (cc == -ENODEV) if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
}
} else {
/* trigger path verification. */
if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
else if (sch->lpm == mask)
goto out_unreg; goto out_unreg;
/* Request retry of internal operation. */
device_set_intretry(sch);
/* Call handler. */
if (sch->driver && sch->driver->termination)
sch->driver->termination(&sch->dev);
goto out_unlock;
} }
/* trigger path verification. */
if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
else if (sch->lpm == mask)
goto out_unreg;
out_unlock:
spin_unlock_irq(sch->lock); spin_unlock_irq(sch->lock);
return 0; return 0;
out_unreg: out_unreg:
spin_unlock_irq(sch->lock);
sch->lpm = 0; sch->lpm = 0;
if (css_enqueue_subchannel_slow(sch->schid)) { if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list(); css_clear_subchannel_slow_list();
need_rescan = 1; need_rescan = 1;
} }
spin_unlock_irq(sch->lock);
return 0; return 0;
} }
...@@ -683,38 +711,6 @@ int chsc_chp_online(struct chp_id chpid) ...@@ -683,38 +711,6 @@ int chsc_chp_online(struct chp_id chpid)
return rc; return rc;
} }
static int check_for_io_on_path(struct subchannel *sch, int index)
{
int cc;
cc = stsch(sch->schid, &sch->schib);
if (cc)
return 0;
if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index))
return 1;
return 0;
}
static void terminate_internal_io(struct subchannel *sch)
{
if (cio_clear(sch)) {
/* Recheck device in case clear failed. */
sch->lpm = 0;
if (device_trigger_verify(sch) != 0) {
if(css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();
need_rescan = 1;
}
}
return;
}
/* Request retry of internal operation. */
device_set_intretry(sch);
/* Call handler. */
if (sch->driver && sch->driver->termination)
sch->driver->termination(&sch->dev);
}
static void __s390_subchannel_vary_chpid(struct subchannel *sch, static void __s390_subchannel_vary_chpid(struct subchannel *sch,
struct chp_id chpid, int on) struct chp_id chpid, int on)
{ {
...@@ -741,13 +737,17 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, ...@@ -741,13 +737,17 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
} }
sch->opm &= ~(0x80 >> chp); sch->opm &= ~(0x80 >> chp);
sch->lpm &= ~(0x80 >> chp); sch->lpm &= ~(0x80 >> chp);
if (check_for_io_on_path(sch, chp)) { if (check_for_io_on_path(sch, (0x80 >> chp))) {
if (device_is_online(sch)) if (device_is_online(sch))
/* Path verification is done after killing. */ /* Path verification is done after killing. */
device_kill_io(sch); device_kill_io(sch);
else else {
/* Kill and retry internal I/O. */ /* Kill and retry internal I/O. */
terminate_internal_io(sch); terminate_internal_io(sch);
/* Re-start path verification. */
if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
}
} else if (!sch->lpm) { } else if (!sch->lpm) {
if (device_trigger_verify(sch) != 0) { if (device_trigger_verify(sch) != 0) {
if (css_enqueue_subchannel_slow(sch->schid)) { if (css_enqueue_subchannel_slow(sch->schid)) {
......
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