aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2009-12-07 06:51:31 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:31 -0500
commit52ef0608e3ee4a511725e443c4b572fece22b353 (patch)
tree08a2d1f3a3015ec4026f229a1994a31d1b7d50e2 /drivers/s390
parent454e1fa1ebae7cff707b2e3f12b775c263c8408b (diff)
[S390] cio: use sense-pgid operation for path verification
Set-pgid operations fail for some device types under z/VM for which the hypervisor has already set the pgid. Also reserved devices or changed pgids are not correctly recognized. Fix these problems by using a combination of sense-pgid and set-pgid and by also accepting pre-defined pgid settings. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/device.h3
-rw-r--r--drivers/s390/cio/device_fsm.c41
-rw-r--r--drivers/s390/cio/device_pgid.c148
-rw-r--r--drivers/s390/cio/io_sch.h1
4 files changed, 99 insertions, 94 deletions
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 4e1775cf9739..2df519bb877e 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -110,9 +110,6 @@ void ccw_device_sense_id_start(struct ccw_device *);
110void ccw_device_sense_id_done(struct ccw_device *, int); 110void ccw_device_sense_id_done(struct ccw_device *, int);
111 111
112/* Function prototypes for path grouping stuff. */ 112/* Function prototypes for path grouping stuff. */
113void ccw_device_sense_pgid_start(struct ccw_device *);
114void ccw_device_sense_pgid_done(struct ccw_device *, int);
115
116void ccw_device_verify_start(struct ccw_device *); 113void ccw_device_verify_start(struct ccw_device *);
117void ccw_device_verify_done(struct ccw_device *, int); 114void ccw_device_verify_done(struct ccw_device *, int);
118 115
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index d6e315dc0f98..8d565ff85e43 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -395,33 +395,6 @@ ccw_device_done(struct ccw_device *cdev, int state)
395} 395}
396 396
397/* 397/*
398 * Function called from device_pgid.c after sense path ground has completed.
399 */
400void
401ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
402{
403 struct subchannel *sch;
404
405 sch = to_subchannel(cdev->dev.parent);
406 switch (err) {
407 case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
408 case 0: /* success */
409 case -EACCES: /* partial success, some paths not operational */
410 break;
411 case -ETIME: /* Sense path group id stopped by timeout. */
412 case -EUSERS: /* device is reserved for someone else. */
413 ccw_device_done(cdev, DEV_STATE_BOXED);
414 return;
415 default:
416 ccw_device_done(cdev, DEV_STATE_NOT_OPER);
417 return;
418 }
419 /* Start Path Group verification. */
420 cdev->private->state = DEV_STATE_VERIFY;
421 ccw_device_verify_start(cdev);
422}
423
424/*
425 * Start device recognition. 398 * Start device recognition.
426 */ 399 */
427void ccw_device_recognition(struct ccw_device *cdev) 400void ccw_device_recognition(struct ccw_device *cdev)
@@ -503,6 +476,7 @@ callback:
503 } 476 }
504 break; 477 break;
505 case -ETIME: 478 case -ETIME:
479 case -EUSERS:
506 /* Reset oper notify indication after verify error. */ 480 /* Reset oper notify indication after verify error. */
507 cdev->private->flags.donotify = 0; 481 cdev->private->flags.donotify = 0;
508 ccw_device_done(cdev, DEV_STATE_BOXED); 482 ccw_device_done(cdev, DEV_STATE_BOXED);
@@ -540,16 +514,9 @@ ccw_device_online(struct ccw_device *cdev)
540 dev_fsm_event(cdev, DEV_EVENT_NOTOPER); 514 dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
541 return ret; 515 return ret;
542 } 516 }
543 /* Do we want to do path grouping? */ 517 /* Start initial path verification. */
544 if (!cdev->private->options.pgroup) { 518 cdev->private->state = DEV_STATE_VERIFY;
545 /* Start initial path verification. */ 519 ccw_device_verify_start(cdev);
546 cdev->private->state = DEV_STATE_VERIFY;
547 ccw_device_verify_start(cdev);
548 return 0;
549 }
550 /* Do a SensePGID first. */
551 cdev->private->state = DEV_STATE_SENSE_PGID;
552 ccw_device_sense_pgid_start(cdev);
553 return 0; 520 return 0;
554} 521}
555 522
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 3323042ba755..4d54abd82b8c 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -141,8 +141,8 @@ static void spid_do(struct ccw_device *cdev)
141 struct ccw_request *req = &cdev->private->req; 141 struct ccw_request *req = &cdev->private->req;
142 u8 fn; 142 u8 fn;
143 143
144 /* Adjust lpm if paths are not set in pam. */ 144 /* Use next available path that is not already in correct state. */
145 req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam); 145 req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & ~sch->vpm);
146 if (!req->lpm) 146 if (!req->lpm)
147 goto out_nopath; 147 goto out_nopath;
148 /* Channel program setup. */ 148 /* Channel program setup. */
@@ -199,6 +199,19 @@ err:
199 verify_done(cdev, rc); 199 verify_done(cdev, rc);
200} 200}
201 201
202static void spid_start(struct ccw_device *cdev)
203{
204 struct ccw_request *req = &cdev->private->req;
205
206 /* Initialize request data. */
207 memset(req, 0, sizeof(*req));
208 req->timeout = PGID_TIMEOUT;
209 req->maxretries = PGID_RETRIES;
210 req->lpm = 0x80;
211 req->callback = spid_callback;
212 spid_do(cdev);
213}
214
202static int pgid_cmp(struct pgid *p1, struct pgid *p2) 215static int pgid_cmp(struct pgid *p1, struct pgid *p2)
203{ 216{
204 return memcmp((char *) p1 + 1, (char *) p2 + 1, 217 return memcmp((char *) p1 + 1, (char *) p2 + 1,
@@ -241,6 +254,40 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
241 *p = first; 254 *p = first;
242} 255}
243 256
257static u8 pgid_to_vpm(struct ccw_device *cdev)
258{
259 struct subchannel *sch = to_subchannel(cdev->dev.parent);
260 struct pgid *pgid;
261 int i;
262 int lpm;
263 u8 vpm = 0;
264
265 /* Set VPM bits for paths which are already in the target state. */
266 for (i = 0; i < 8; i++) {
267 lpm = 0x80 >> i;
268 if ((cdev->private->pgid_valid_mask & lpm) == 0)
269 continue;
270 pgid = &cdev->private->pgid[i];
271 if (sch->opm & lpm) {
272 if (pgid->inf.ps.state1 != SNID_STATE1_GROUPED)
273 continue;
274 } else {
275 if (pgid->inf.ps.state1 != SNID_STATE1_UNGROUPED)
276 continue;
277 }
278 if (cdev->private->flags.mpath) {
279 if (pgid->inf.ps.state3 != SNID_STATE3_MULTI_PATH)
280 continue;
281 } else {
282 if (pgid->inf.ps.state3 != SNID_STATE3_SINGLE_PATH)
283 continue;
284 }
285 vpm |= lpm;
286 }
287
288 return vpm;
289}
290
244static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid) 291static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid)
245{ 292{
246 int i; 293 int i;
@@ -255,6 +302,7 @@ static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid)
255static void snid_done(struct ccw_device *cdev, int rc) 302static void snid_done(struct ccw_device *cdev, int rc)
256{ 303{
257 struct ccw_dev_id *id = &cdev->private->dev_id; 304 struct ccw_dev_id *id = &cdev->private->dev_id;
305 struct subchannel *sch = to_subchannel(cdev->dev.parent);
258 struct pgid *pgid; 306 struct pgid *pgid;
259 int mismatch = 0; 307 int mismatch = 0;
260 int reserved = 0; 308 int reserved = 0;
@@ -263,18 +311,38 @@ static void snid_done(struct ccw_device *cdev, int rc)
263 if (rc) 311 if (rc)
264 goto out; 312 goto out;
265 pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset); 313 pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset);
266 if (!mismatch) {
267 pgid_fill(cdev, pgid);
268 cdev->private->flags.pgid_rdy = 1;
269 }
270 if (reserved) 314 if (reserved)
271 rc = -EUSERS; 315 rc = -EUSERS;
316 else if (mismatch)
317 rc = -EOPNOTSUPP;
318 else {
319 sch->vpm = pgid_to_vpm(cdev);
320 pgid_fill(cdev, pgid);
321 }
272out: 322out:
273 CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x mism=%d " 323 CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x "
274 "rsvd=%d reset=%d\n", id->ssid, id->devno, rc, 324 "mism=%d rsvd=%d reset=%d\n", id->ssid, id->devno, rc,
275 cdev->private->pgid_valid_mask, mismatch, reserved, 325 cdev->private->pgid_valid_mask, sch->vpm, mismatch,
276 reset); 326 reserved, reset);
277 ccw_device_sense_pgid_done(cdev, rc); 327 switch (rc) {
328 case 0:
329 /* Anything left to do? */
330 if (sch->vpm == sch->schib.pmcw.pam) {
331 verify_done(cdev, sch->vpm == 0 ? -EACCES : 0);
332 return;
333 }
334 /* Perform path-grouping. */
335 spid_start(cdev);
336 break;
337 case -EOPNOTSUPP:
338 /* Path-grouping not supported. */
339 cdev->private->flags.pgroup = 0;
340 cdev->private->flags.mpath = 0;
341 verify_start(cdev);
342 break;
343 default:
344 verify_done(cdev, rc);
345 }
278} 346}
279 347
280/* 348/*
@@ -333,33 +401,6 @@ err:
333 snid_done(cdev, rc); 401 snid_done(cdev, rc);
334} 402}
335 403
336/**
337 * ccw_device_sense_pgid_start - perform SENSE PGID
338 * @cdev: ccw device
339 *
340 * Execute a SENSE PGID channel program on each path to @cdev to update its
341 * PGID information. When finished, call ccw_device_sense_id_done with a
342 * return code specifying the result.
343 */
344void ccw_device_sense_pgid_start(struct ccw_device *cdev)
345{
346 struct ccw_request *req = &cdev->private->req;
347
348 CIO_TRACE_EVENT(4, "snid");
349 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
350 /* Initialize PGID data. */
351 memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
352 cdev->private->flags.pgid_rdy = 0;
353 cdev->private->pgid_valid_mask = 0;
354 /* Initialize request data. */
355 memset(req, 0, sizeof(*req));
356 req->timeout = PGID_TIMEOUT;
357 req->maxretries = PGID_RETRIES;
358 req->callback = snid_callback;
359 req->lpm = 0x80;
360 snid_do(cdev);
361}
362
363/* 404/*
364 * Perform path verification. 405 * Perform path verification.
365 */ 406 */
@@ -367,6 +408,7 @@ static void verify_start(struct ccw_device *cdev)
367{ 408{
368 struct subchannel *sch = to_subchannel(cdev->dev.parent); 409 struct subchannel *sch = to_subchannel(cdev->dev.parent);
369 struct ccw_request *req = &cdev->private->req; 410 struct ccw_request *req = &cdev->private->req;
411 struct ccw_dev_id *devid = &cdev->private->dev_id;
370 412
371 sch->vpm = 0; 413 sch->vpm = 0;
372 /* Initialize request data. */ 414 /* Initialize request data. */
@@ -375,9 +417,13 @@ static void verify_start(struct ccw_device *cdev)
375 req->maxretries = PGID_RETRIES; 417 req->maxretries = PGID_RETRIES;
376 req->lpm = 0x80; 418 req->lpm = 0x80;
377 if (cdev->private->flags.pgroup) { 419 if (cdev->private->flags.pgroup) {
378 req->callback = spid_callback; 420 CIO_TRACE_EVENT(4, "snid");
379 spid_do(cdev); 421 CIO_HEX_EVENT(4, devid, sizeof(*devid));
422 req->callback = snid_callback;
423 snid_do(cdev);
380 } else { 424 } else {
425 CIO_TRACE_EVENT(4, "nop");
426 CIO_HEX_EVENT(4, devid, sizeof(*devid));
381 req->filter = nop_filter; 427 req->filter = nop_filter;
382 req->callback = nop_callback; 428 req->callback = nop_callback;
383 nop_do(cdev); 429 nop_do(cdev);
@@ -398,19 +444,15 @@ void ccw_device_verify_start(struct ccw_device *cdev)
398{ 444{
399 CIO_TRACE_EVENT(4, "vrfy"); 445 CIO_TRACE_EVENT(4, "vrfy");
400 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); 446 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
401 if (!cdev->private->flags.pgid_rdy) { 447 /* Initialize PGID data. */
402 /* No pathgrouping possible. */ 448 memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
403 cdev->private->flags.pgroup = 0; 449 cdev->private->pgid_valid_mask = 0;
404 cdev->private->flags.mpath = 0; 450 /*
405 } else { 451 * Initialize pathgroup and multipath state with target values.
406 /* 452 * They may change in the course of path verification.
407 * Initialize pathgroup and multipath state with target values. 453 */
408 * They may change in the course of path verification. 454 cdev->private->flags.pgroup = cdev->private->options.pgroup;
409 */ 455 cdev->private->flags.mpath = cdev->private->options.mpath;
410 cdev->private->flags.pgroup = cdev->private->options.pgroup;
411 cdev->private->flags.mpath = cdev->private->options.mpath;
412
413 }
414 cdev->private->flags.doverify = 0; 456 cdev->private->flags.doverify = 0;
415 verify_start(cdev); 457 verify_start(cdev);
416} 458}
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index b387c80d1888..0559479073cc 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -166,7 +166,6 @@ struct ccw_device_private {
166 unsigned int recog_done:1; /* dev. recog. complete */ 166 unsigned int recog_done:1; /* dev. recog. complete */
167 unsigned int fake_irb:1; /* deliver faked irb */ 167 unsigned int fake_irb:1; /* deliver faked irb */
168 unsigned int resuming:1; /* recognition while resume */ 168 unsigned int resuming:1; /* recognition while resume */
169 unsigned int pgid_rdy:1; /* pgids are ready */
170 unsigned int pgroup:1; /* pathgroup is set up */ 169 unsigned int pgroup:1; /* pathgroup is set up */
171 unsigned int mpath:1; /* multipathing is set up */ 170 unsigned int mpath:1; /* multipathing is set up */
172 } __attribute__((packed)) flags; 171 } __attribute__((packed)) flags;