diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2013-01-28 13:29:43 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-02-14 09:55:07 -0500 |
commit | 69f5576f6c8c9d0f0b3670ee7c807a194b4c40f4 (patch) | |
tree | 0872aa245fb0c5b0a4decb14e7bd71726baa995e /drivers/s390 | |
parent | b4b3d128c821d70112ac0096d5c1440f5ed9f718 (diff) |
s390/cio: dont abort verification after missing irq
Do not abort path verification when waiting for an interrupt timed out.
Use path_noirq_mask to keep track of the paths used for this (also
maintain a path_notoper_mask for debugging purposes). If the timeout
happend to be during an operation where we query or alter the state of
path groups set the pgid_unknown flag.
With this change we allow usage of devices which have such ill-behaved
paths (if at least one path is operational).
Reviewed-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 48 | ||||
-rw-r--r-- | drivers/s390/cio/io_sch.h | 5 |
2 files changed, 43 insertions, 10 deletions
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 908d287f66c1..6f2987d8da99 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -102,10 +102,20 @@ static void nop_callback(struct ccw_device *cdev, void *data, int rc) | |||
102 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | 102 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
103 | struct ccw_request *req = &cdev->private->req; | 103 | struct ccw_request *req = &cdev->private->req; |
104 | 104 | ||
105 | if (rc == 0) | 105 | switch (rc) { |
106 | case 0: | ||
106 | sch->vpm |= req->lpm; | 107 | sch->vpm |= req->lpm; |
107 | else if (rc != -EACCES) | 108 | break; |
109 | case -ETIME: | ||
110 | cdev->private->path_noirq_mask |= req->lpm; | ||
111 | break; | ||
112 | case -EACCES: | ||
113 | cdev->private->path_notoper_mask |= req->lpm; | ||
114 | break; | ||
115 | default: | ||
108 | goto err; | 116 | goto err; |
117 | } | ||
118 | /* Continue on the next path. */ | ||
109 | req->lpm >>= 1; | 119 | req->lpm >>= 1; |
110 | nop_do(cdev); | 120 | nop_do(cdev); |
111 | return; | 121 | return; |
@@ -174,7 +184,12 @@ static void spid_callback(struct ccw_device *cdev, void *data, int rc) | |||
174 | case 0: | 184 | case 0: |
175 | sch->vpm |= req->lpm & sch->opm; | 185 | sch->vpm |= req->lpm & sch->opm; |
176 | break; | 186 | break; |
187 | case -ETIME: | ||
188 | cdev->private->flags.pgid_unknown = 1; | ||
189 | cdev->private->path_noirq_mask |= req->lpm; | ||
190 | break; | ||
177 | case -EACCES: | 191 | case -EACCES: |
192 | cdev->private->path_notoper_mask |= req->lpm; | ||
178 | break; | 193 | break; |
179 | case -EOPNOTSUPP: | 194 | case -EOPNOTSUPP: |
180 | if (cdev->private->flags.mpath) { | 195 | if (cdev->private->flags.mpath) { |
@@ -404,10 +419,21 @@ static void snid_callback(struct ccw_device *cdev, void *data, int rc) | |||
404 | { | 419 | { |
405 | struct ccw_request *req = &cdev->private->req; | 420 | struct ccw_request *req = &cdev->private->req; |
406 | 421 | ||
407 | if (rc == 0) | 422 | switch (rc) { |
423 | case 0: | ||
408 | cdev->private->pgid_valid_mask |= req->lpm; | 424 | cdev->private->pgid_valid_mask |= req->lpm; |
409 | else if (rc != -EACCES) | 425 | break; |
426 | case -ETIME: | ||
427 | cdev->private->flags.pgid_unknown = 1; | ||
428 | cdev->private->path_noirq_mask |= req->lpm; | ||
429 | break; | ||
430 | case -EACCES: | ||
431 | cdev->private->path_notoper_mask |= req->lpm; | ||
432 | break; | ||
433 | default: | ||
410 | goto err; | 434 | goto err; |
435 | } | ||
436 | /* Continue on the next path. */ | ||
411 | req->lpm >>= 1; | 437 | req->lpm >>= 1; |
412 | snid_do(cdev); | 438 | snid_do(cdev); |
413 | return; | 439 | return; |
@@ -427,6 +453,13 @@ static void verify_start(struct ccw_device *cdev) | |||
427 | 453 | ||
428 | sch->vpm = 0; | 454 | sch->vpm = 0; |
429 | sch->lpm = sch->schib.pmcw.pam; | 455 | sch->lpm = sch->schib.pmcw.pam; |
456 | |||
457 | /* Initialize PGID data. */ | ||
458 | memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid)); | ||
459 | cdev->private->pgid_valid_mask = 0; | ||
460 | cdev->private->pgid_todo_mask = sch->schib.pmcw.pam; | ||
461 | cdev->private->path_notoper_mask = 0; | ||
462 | |||
430 | /* Initialize request data. */ | 463 | /* Initialize request data. */ |
431 | memset(req, 0, sizeof(*req)); | 464 | memset(req, 0, sizeof(*req)); |
432 | req->timeout = PGID_TIMEOUT; | 465 | req->timeout = PGID_TIMEOUT; |
@@ -459,14 +492,8 @@ static void verify_start(struct ccw_device *cdev) | |||
459 | */ | 492 | */ |
460 | void ccw_device_verify_start(struct ccw_device *cdev) | 493 | void ccw_device_verify_start(struct ccw_device *cdev) |
461 | { | 494 | { |
462 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
463 | |||
464 | CIO_TRACE_EVENT(4, "vrfy"); | 495 | CIO_TRACE_EVENT(4, "vrfy"); |
465 | CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); | 496 | CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); |
466 | /* Initialize PGID data. */ | ||
467 | memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid)); | ||
468 | cdev->private->pgid_valid_mask = 0; | ||
469 | cdev->private->pgid_todo_mask = sch->schib.pmcw.pam; | ||
470 | /* | 497 | /* |
471 | * Initialize pathgroup and multipath state with target values. | 498 | * Initialize pathgroup and multipath state with target values. |
472 | * They may change in the course of path verification. | 499 | * They may change in the course of path verification. |
@@ -474,6 +501,7 @@ void ccw_device_verify_start(struct ccw_device *cdev) | |||
474 | cdev->private->flags.pgroup = cdev->private->options.pgroup; | 501 | cdev->private->flags.pgroup = cdev->private->options.pgroup; |
475 | cdev->private->flags.mpath = cdev->private->options.mpath; | 502 | cdev->private->flags.mpath = cdev->private->options.mpath; |
476 | cdev->private->flags.doverify = 0; | 503 | cdev->private->flags.doverify = 0; |
504 | cdev->private->path_noirq_mask = 0; | ||
477 | verify_start(cdev); | 505 | verify_start(cdev); |
478 | } | 506 | } |
479 | 507 | ||
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index 76253dfcc1be..b108f4a5c7dd 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h | |||
@@ -126,6 +126,10 @@ struct ccw_device_private { | |||
126 | u8 pgid_valid_mask; /* mask of valid PGIDs */ | 126 | u8 pgid_valid_mask; /* mask of valid PGIDs */ |
127 | u8 pgid_todo_mask; /* mask of PGIDs to be adjusted */ | 127 | u8 pgid_todo_mask; /* mask of PGIDs to be adjusted */ |
128 | u8 pgid_reset_mask; /* mask of PGIDs which were reset */ | 128 | u8 pgid_reset_mask; /* mask of PGIDs which were reset */ |
129 | u8 path_noirq_mask; /* mask of paths for which no irq was | ||
130 | received */ | ||
131 | u8 path_notoper_mask; /* mask of paths which were found | ||
132 | not operable */ | ||
129 | u8 path_gone_mask; /* mask of paths, that became unavailable */ | 133 | u8 path_gone_mask; /* mask of paths, that became unavailable */ |
130 | u8 path_new_mask; /* mask of paths, that became available */ | 134 | u8 path_new_mask; /* mask of paths, that became available */ |
131 | struct { | 135 | struct { |
@@ -145,6 +149,7 @@ struct ccw_device_private { | |||
145 | unsigned int resuming:1; /* recognition while resume */ | 149 | unsigned int resuming:1; /* recognition while resume */ |
146 | unsigned int pgroup:1; /* pathgroup is set up */ | 150 | unsigned int pgroup:1; /* pathgroup is set up */ |
147 | unsigned int mpath:1; /* multipathing is set up */ | 151 | unsigned int mpath:1; /* multipathing is set up */ |
152 | unsigned int pgid_unknown:1;/* unknown pgid state */ | ||
148 | unsigned int initialized:1; /* set if initial reference held */ | 153 | unsigned int initialized:1; /* set if initial reference held */ |
149 | } __attribute__((packed)) flags; | 154 | } __attribute__((packed)) flags; |
150 | unsigned long intparm; /* user interruption parameter */ | 155 | unsigned long intparm; /* user interruption parameter */ |