s390/cio: improve cio_commit_config
The modify subchannel wrapper cio_commit_config can fail when (unexpected) status is pending on the subchannel. Callers of cio_commit_config (that operated on enabled subchannels) needed to do error handling for that case (clear the unexpected status with test subchannel and retry). This error handling is missing in some code paths and caused online setting of devices to fail. Fix this for all callers by moving the error handling inside cio_commit_config. Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com> Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
8d7f6690ce
commit
1bc8927cc5
|
@ -342,8 +342,9 @@ static int cio_check_config(struct subchannel *sch, struct schib *schib)
|
|||
*/
|
||||
int cio_commit_config(struct subchannel *sch)
|
||||
{
|
||||
struct schib schib;
|
||||
int ccode, retry, ret = 0;
|
||||
struct schib schib;
|
||||
struct irb irb;
|
||||
|
||||
if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
|
||||
return -ENODEV;
|
||||
|
@ -367,7 +368,10 @@ int cio_commit_config(struct subchannel *sch)
|
|||
ret = -EAGAIN;
|
||||
break;
|
||||
case 1: /* status pending */
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
if (tsch(sch->schid, &irb))
|
||||
return ret;
|
||||
break;
|
||||
case 2: /* busy */
|
||||
udelay(100); /* allow for recovery */
|
||||
ret = -EBUSY;
|
||||
|
@ -403,7 +407,6 @@ EXPORT_SYMBOL_GPL(cio_update_schib);
|
|||
*/
|
||||
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
|
||||
{
|
||||
int retry;
|
||||
int ret;
|
||||
|
||||
CIO_TRACE_EVENT(2, "ensch");
|
||||
|
@ -418,20 +421,14 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
|
|||
sch->config.isc = sch->isc;
|
||||
sch->config.intparm = intparm;
|
||||
|
||||
for (retry = 0; retry < 3; retry++) {
|
||||
ret = cio_commit_config(sch);
|
||||
if (ret == -EIO) {
|
||||
/*
|
||||
* Got a program check in msch. Try without
|
||||
* the concurrent sense bit the next time.
|
||||
*/
|
||||
sch->config.csense = 0;
|
||||
ret = cio_commit_config(sch);
|
||||
if (ret == -EIO) {
|
||||
/*
|
||||
* Got a program check in msch. Try without
|
||||
* the concurrent sense bit the next time.
|
||||
*/
|
||||
sch->config.csense = 0;
|
||||
} else if (ret == -EBUSY) {
|
||||
struct irb irb;
|
||||
if (tsch(sch->schid, &irb) != 0)
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
CIO_HEX_EVENT(2, &ret, sizeof(ret));
|
||||
return ret;
|
||||
|
@ -444,7 +441,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
|
|||
*/
|
||||
int cio_disable_subchannel(struct subchannel *sch)
|
||||
{
|
||||
int retry;
|
||||
int ret;
|
||||
|
||||
CIO_TRACE_EVENT(2, "dissch");
|
||||
|
@ -456,16 +452,8 @@ int cio_disable_subchannel(struct subchannel *sch)
|
|||
return -ENODEV;
|
||||
|
||||
sch->config.ena = 0;
|
||||
ret = cio_commit_config(sch);
|
||||
|
||||
for (retry = 0; retry < 3; retry++) {
|
||||
ret = cio_commit_config(sch);
|
||||
if (ret == -EBUSY) {
|
||||
struct irb irb;
|
||||
if (tsch(sch->schid, &irb) != 0)
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
CIO_HEX_EVENT(2, &ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue