aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2013-01-28 13:32:56 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-02-14 09:55:09 -0500
commit88e7616e407fd60ad96e71349393397cf72f8b8d (patch)
tree665ac35e47f257e8b550a9c3a7a8bd5f177d0a32
parent84c57ad5d938ff28d85ac93b79c1f918a767a23e (diff)
s390/cio: handle unknown pgroup state
When an attempt to query or modify the grouping state of a channel path fails due to a timeout, we cannot be sure about its state. To get back to a defined state, disband the whole path group and try again while excluding the offending path. 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>
-rw-r--r--drivers/s390/cio/device_pgid.c64
1 files changed, 61 insertions, 3 deletions
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index f12beb72f263..37ada05e82a5 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -23,6 +23,8 @@
23#define PGID_RETRIES 256 23#define PGID_RETRIES 256
24#define PGID_TIMEOUT (10 * HZ) 24#define PGID_TIMEOUT (10 * HZ)
25 25
26static void verify_start(struct ccw_device *cdev);
27
26/* 28/*
27 * Process path verification data and report result. 29 * Process path verification data and report result.
28 */ 30 */
@@ -142,6 +144,48 @@ static void spid_build_cp(struct ccw_device *cdev, u8 fn)
142 req->cp = cp; 144 req->cp = cp;
143} 145}
144 146
147static void pgid_wipeout_callback(struct ccw_device *cdev, void *data, int rc)
148{
149 if (rc) {
150 /* We don't know the path groups' state. Abort. */
151 verify_done(cdev, rc);
152 return;
153 }
154 /*
155 * Path groups have been reset. Restart path verification but
156 * leave paths in path_noirq_mask out.
157 */
158 cdev->private->flags.pgid_unknown = 0;
159 verify_start(cdev);
160}
161
162/*
163 * Reset pathgroups and restart path verification, leave unusable paths out.
164 */
165static void pgid_wipeout_start(struct ccw_device *cdev)
166{
167 struct subchannel *sch = to_subchannel(cdev->dev.parent);
168 struct ccw_dev_id *id = &cdev->private->dev_id;
169 struct ccw_request *req = &cdev->private->req;
170 u8 fn;
171
172 CIO_MSG_EVENT(2, "wipe: device 0.%x.%04x: pvm=%02x nim=%02x\n",
173 id->ssid, id->devno, cdev->private->pgid_valid_mask,
174 cdev->private->path_noirq_mask);
175
176 /* Initialize request data. */
177 memset(req, 0, sizeof(*req));
178 req->timeout = PGID_TIMEOUT;
179 req->maxretries = PGID_RETRIES;
180 req->lpm = sch->schib.pmcw.pam;
181 req->callback = pgid_wipeout_callback;
182 fn = SPID_FUNC_DISBAND;
183 if (cdev->private->flags.mpath)
184 fn |= SPID_FUNC_MULTI_PATH;
185 spid_build_cp(cdev, fn);
186 ccw_request_start(cdev);
187}
188
145/* 189/*
146 * Perform establish/resign SET PGID on a single path. 190 * Perform establish/resign SET PGID on a single path.
147 */ 191 */
@@ -167,11 +211,14 @@ static void spid_do(struct ccw_device *cdev)
167 return; 211 return;
168 212
169out_nopath: 213out_nopath:
214 if (cdev->private->flags.pgid_unknown) {
215 /* At least one SPID could be partially done. */
216 pgid_wipeout_start(cdev);
217 return;
218 }
170 verify_done(cdev, sch->vpm ? 0 : -EACCES); 219 verify_done(cdev, sch->vpm ? 0 : -EACCES);
171} 220}
172 221
173static void verify_start(struct ccw_device *cdev);
174
175/* 222/*
176 * Process SET PGID request result for a single path. 223 * Process SET PGID request result for a single path.
177 */ 224 */
@@ -357,6 +404,10 @@ out:
357 cdev->private->pgid_todo_mask, mismatch, reserved, reset); 404 cdev->private->pgid_todo_mask, mismatch, reserved, reset);
358 switch (rc) { 405 switch (rc) {
359 case 0: 406 case 0:
407 if (cdev->private->flags.pgid_unknown) {
408 pgid_wipeout_start(cdev);
409 return;
410 }
360 /* Anything left to do? */ 411 /* Anything left to do? */
361 if (cdev->private->pgid_todo_mask == 0) { 412 if (cdev->private->pgid_todo_mask == 0) {
362 verify_done(cdev, sch->vpm == 0 ? -EACCES : 0); 413 verify_done(cdev, sch->vpm == 0 ? -EACCES : 0);
@@ -400,6 +451,7 @@ static void snid_do(struct ccw_device *cdev)
400{ 451{
401 struct subchannel *sch = to_subchannel(cdev->dev.parent); 452 struct subchannel *sch = to_subchannel(cdev->dev.parent);
402 struct ccw_request *req = &cdev->private->req; 453 struct ccw_request *req = &cdev->private->req;
454 int ret;
403 455
404 req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & 456 req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam &
405 ~cdev->private->path_noirq_mask); 457 ~cdev->private->path_noirq_mask);
@@ -410,7 +462,13 @@ static void snid_do(struct ccw_device *cdev)
410 return; 462 return;
411 463
412out_nopath: 464out_nopath:
413 snid_done(cdev, cdev->private->pgid_valid_mask ? 0 : -EACCES); 465 if (cdev->private->pgid_valid_mask)
466 ret = 0;
467 else if (cdev->private->path_noirq_mask)
468 ret = -ETIME;
469 else
470 ret = -EACCES;
471 snid_done(cdev, ret);
414} 472}
415 473
416/* 474/*