[S390] cio: introduce cio_update_schib
There is the chance that we get condition code 0 for a stsch but
the resulting schib is not vaild. In the current code there are
2 cases:
* we do a check for validity of the schib after stsch, but at this
time we have already stored the invaild schib in the subchannel
structure. This may lead to problems.
* we don't do a check for validity, which is not that good either.
The patch addresses both issues by introducing the stsch wrapper
cio_update_schib which performs stsch on a local schib. This schib
is only written back to the subchannel if it's valid.
side note: For some functions (chp_events) the return codes are
different now (-ENXIO vs -ENODEV) but this shouldn't do harm
since the caller doesn't check for _specific_ errors.
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 01330cf..e1a3786 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -140,8 +140,7 @@
int ret;
sch = to_subchannel(cdev->dev.parent);
- ret = stsch(sch->schid, &sch->schib);
- if (ret || !sch->schib.pmcw.dnv)
+ if (cio_update_schib(sch))
return -ENODEV;
if (!sch->schib.pmcw.ena)
/* Not operational -> done. */
@@ -245,11 +244,13 @@
* through ssch() and the path information is up to date.
*/
old_lpm = sch->lpm;
- stsch(sch->schid, &sch->schib);
- sch->lpm = sch->schib.pmcw.pam & sch->opm;
+
/* Check since device may again have become not operational. */
- if (!sch->schib.pmcw.dnv)
+ if (cio_update_schib(sch))
state = DEV_STATE_NOT_OPER;
+ else
+ sch->lpm = sch->schib.pmcw.pam & sch->opm;
+
if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
/* Force reprobe on all chpids. */
old_lpm = 0;
@@ -549,7 +550,11 @@
sch = to_subchannel(cdev->dev.parent);
/* Update schib - pom may have changed. */
- stsch(sch->schid, &sch->schib);
+ if (cio_update_schib(sch)) {
+ cdev->private->flags.donotify = 0;
+ ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+ return;
+ }
/* Update lpm with verified path mask. */
sch->lpm = sch->vpm;
/* Repeat path verification? */
@@ -667,7 +672,7 @@
return 0;
}
sch = to_subchannel(cdev->dev.parent);
- if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
+ if (cio_update_schib(sch))
return -ENODEV;
if (scsw_actl(&sch->schib.scsw) != 0)
return -EBUSY;
@@ -745,7 +750,10 @@
* Since we might not just be coming from an interrupt from the
* subchannel we have to update the schib.
*/
- stsch(sch->schid, &sch->schib);
+ if (cio_update_schib(sch)) {
+ ccw_device_verify_done(cdev, -ENODEV);
+ return;
+ }
if (scsw_actl(&sch->schib.scsw) != 0 ||
(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) ||
@@ -1011,9 +1019,7 @@
sch = to_subchannel(cdev->dev.parent);
/* Update some values. */
- if (stsch(sch->schid, &sch->schib))
- return;
- if (!sch->schib.pmcw.dnv)
+ if (cio_update_schib(sch))
return;
/*
* The pim, pam, pom values may not be accurate, but they are the best