diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2009-12-07 06:51:30 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2009-12-07 06:51:31 -0500 |
commit | 454e1fa1ebae7cff707b2e3f12b775c263c8408b (patch) | |
tree | eab290fcacd6faaf7e01e3a637cb9678bb367c66 /drivers/s390/cio/device_pgid.c | |
parent | 4257aaecffab77bad43e12057f56a5590b360f9f (diff) |
[S390] cio: split PGID settings and status
Split setting (driver wants feature enabled) and status (feature
setup was successful) for PGID related ccw device features so that
setup errors can be detected. Previously, incorrectly handled setup
errors could in rare cases lead to erratic I/O behavior and
permanently unusuable devices.
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/device_pgid.c')
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 33 |
1 files changed, 20 insertions, 13 deletions
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index ce493144b054..3323042ba755 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -30,8 +30,8 @@ static void verify_done(struct ccw_device *cdev, int rc) | |||
30 | { | 30 | { |
31 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | 31 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
32 | struct ccw_dev_id *id = &cdev->private->dev_id; | 32 | struct ccw_dev_id *id = &cdev->private->dev_id; |
33 | int mpath = !cdev->private->flags.pgid_single; | 33 | int mpath = cdev->private->flags.mpath; |
34 | int pgroup = cdev->private->options.pgroup; | 34 | int pgroup = cdev->private->flags.pgroup; |
35 | 35 | ||
36 | if (rc) | 36 | if (rc) |
37 | goto out; | 37 | goto out; |
@@ -150,7 +150,7 @@ static void spid_do(struct ccw_device *cdev) | |||
150 | fn = SPID_FUNC_ESTABLISH; | 150 | fn = SPID_FUNC_ESTABLISH; |
151 | else | 151 | else |
152 | fn = SPID_FUNC_RESIGN; | 152 | fn = SPID_FUNC_RESIGN; |
153 | if (!cdev->private->flags.pgid_single) | 153 | if (cdev->private->flags.mpath) |
154 | fn |= SPID_FUNC_MULTI_PATH; | 154 | fn |= SPID_FUNC_MULTI_PATH; |
155 | spid_build_cp(cdev, fn); | 155 | spid_build_cp(cdev, fn); |
156 | ccw_request_start(cdev); | 156 | ccw_request_start(cdev); |
@@ -177,13 +177,13 @@ static void spid_callback(struct ccw_device *cdev, void *data, int rc) | |||
177 | case -EACCES: | 177 | case -EACCES: |
178 | break; | 178 | break; |
179 | case -EOPNOTSUPP: | 179 | case -EOPNOTSUPP: |
180 | if (!cdev->private->flags.pgid_single) { | 180 | if (cdev->private->flags.mpath) { |
181 | /* Try without multipathing. */ | 181 | /* Try without multipathing. */ |
182 | cdev->private->flags.pgid_single = 1; | 182 | cdev->private->flags.mpath = 0; |
183 | goto out_restart; | 183 | goto out_restart; |
184 | } | 184 | } |
185 | /* Try without pathgrouping. */ | 185 | /* Try without pathgrouping. */ |
186 | cdev->private->options.pgroup = 0; | 186 | cdev->private->flags.pgroup = 0; |
187 | goto out_restart; | 187 | goto out_restart; |
188 | default: | 188 | default: |
189 | goto err; | 189 | goto err; |
@@ -374,7 +374,7 @@ static void verify_start(struct ccw_device *cdev) | |||
374 | req->timeout = PGID_TIMEOUT; | 374 | req->timeout = PGID_TIMEOUT; |
375 | req->maxretries = PGID_RETRIES; | 375 | req->maxretries = PGID_RETRIES; |
376 | req->lpm = 0x80; | 376 | req->lpm = 0x80; |
377 | if (cdev->private->options.pgroup) { | 377 | if (cdev->private->flags.pgroup) { |
378 | req->callback = spid_callback; | 378 | req->callback = spid_callback; |
379 | spid_do(cdev); | 379 | spid_do(cdev); |
380 | } else { | 380 | } else { |
@@ -400,10 +400,17 @@ void ccw_device_verify_start(struct ccw_device *cdev) | |||
400 | CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); | 400 | CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); |
401 | if (!cdev->private->flags.pgid_rdy) { | 401 | if (!cdev->private->flags.pgid_rdy) { |
402 | /* No pathgrouping possible. */ | 402 | /* No pathgrouping possible. */ |
403 | cdev->private->options.pgroup = 0; | 403 | cdev->private->flags.pgroup = 0; |
404 | cdev->private->flags.pgid_single = 1; | 404 | cdev->private->flags.mpath = 0; |
405 | } else | 405 | } else { |
406 | cdev->private->flags.pgid_single = 0; | 406 | /* |
407 | * Initialize pathgroup and multipath state with target values. | ||
408 | * They may change in the course of path verification. | ||
409 | */ | ||
410 | cdev->private->flags.pgroup = cdev->private->options.pgroup; | ||
411 | cdev->private->flags.mpath = cdev->private->options.mpath; | ||
412 | |||
413 | } | ||
407 | cdev->private->flags.doverify = 0; | 414 | cdev->private->flags.doverify = 0; |
408 | verify_start(cdev); | 415 | verify_start(cdev); |
409 | } | 416 | } |
@@ -419,7 +426,7 @@ static void disband_callback(struct ccw_device *cdev, void *data, int rc) | |||
419 | if (rc) | 426 | if (rc) |
420 | goto out; | 427 | goto out; |
421 | /* Ensure consistent multipathing state at device and channel. */ | 428 | /* Ensure consistent multipathing state at device and channel. */ |
422 | cdev->private->flags.pgid_single = 1; | 429 | cdev->private->flags.mpath = 0; |
423 | if (sch->config.mp) { | 430 | if (sch->config.mp) { |
424 | sch->config.mp = 0; | 431 | sch->config.mp = 0; |
425 | rc = cio_commit_config(sch); | 432 | rc = cio_commit_config(sch); |
@@ -453,7 +460,7 @@ void ccw_device_disband_start(struct ccw_device *cdev) | |||
453 | req->lpm = sch->schib.pmcw.pam & sch->opm; | 460 | req->lpm = sch->schib.pmcw.pam & sch->opm; |
454 | req->callback = disband_callback; | 461 | req->callback = disband_callback; |
455 | fn = SPID_FUNC_DISBAND; | 462 | fn = SPID_FUNC_DISBAND; |
456 | if (!cdev->private->flags.pgid_single) | 463 | if (cdev->private->flags.mpath) |
457 | fn |= SPID_FUNC_MULTI_PATH; | 464 | fn |= SPID_FUNC_MULTI_PATH; |
458 | spid_build_cp(cdev, fn); | 465 | spid_build_cp(cdev, fn); |
459 | ccw_request_start(cdev); | 466 | ccw_request_start(cdev); |