aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2006-09-20 09:59:59 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-09-20 09:59:59 -0400
commit28bdc6f6233f380ddc0b430cabd88ffeafea34c7 (patch)
treebe2c8e7943dab4328fcbe18cd6e03c50a82e0f34 /drivers/s390/cio
parente0e32c8eba86fd5ea79eefad6f2c0b4988dfd02a (diff)
[S390] cio: always query all paths on path verification.
Reappearing channel paths are sometimes not utilized by CCW devices because path verification incorrectly relies on path-operational-mask information which is not updated until a channel path has been used again. Modify path verification procedure to always query all available paths to a device. 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')
-rw-r--r--drivers/s390/cio/chsc.c2
-rw-r--r--drivers/s390/cio/cio.c5
-rw-r--r--drivers/s390/cio/device_fsm.c39
-rw-r--r--drivers/s390/cio/device_ops.c2
-rw-r--r--drivers/s390/cio/device_pgid.c81
5 files changed, 68 insertions, 61 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 9f9134b67e40..3bb4e472d73d 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -256,7 +256,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
256 /* trigger path verification. */ 256 /* trigger path verification. */
257 if (sch->driver && sch->driver->verify) 257 if (sch->driver && sch->driver->verify)
258 sch->driver->verify(&sch->dev); 258 sch->driver->verify(&sch->dev);
259 else if (sch->vpm == mask) 259 else if (sch->lpm == mask)
260 goto out_unreg; 260 goto out_unreg;
261out_unlock: 261out_unlock:
262 spin_unlock_irq(&sch->lock); 262 spin_unlock_irq(&sch->lock);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 54cce542a1ee..2e2882daefbb 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -569,10 +569,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
569 sch->opm = 0xff; 569 sch->opm = 0xff;
570 if (!cio_is_console(sch->schid)) 570 if (!cio_is_console(sch->schid))
571 chsc_validate_chpids(sch); 571 chsc_validate_chpids(sch);
572 sch->lpm = sch->schib.pmcw.pim & 572 sch->lpm = sch->schib.pmcw.pam & sch->opm;
573 sch->schib.pmcw.pam &
574 sch->schib.pmcw.pom &
575 sch->opm;
576 573
577 CIO_DEBUG(KERN_INFO, 0, 574 CIO_DEBUG(KERN_INFO, 0,
578 "Detected device %04x on subchannel 0.%x.%04X" 575 "Detected device %04x on subchannel 0.%x.%04X"
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 7756f324fb6f..dace46fc32e8 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -232,10 +232,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
232 */ 232 */
233 old_lpm = sch->lpm; 233 old_lpm = sch->lpm;
234 stsch(sch->schid, &sch->schib); 234 stsch(sch->schid, &sch->schib);
235 sch->lpm = sch->schib.pmcw.pim & 235 sch->lpm = sch->schib.pmcw.pam & sch->opm;
236 sch->schib.pmcw.pam &
237 sch->schib.pmcw.pom &
238 sch->opm;
239 /* Check since device may again have become not operational. */ 236 /* Check since device may again have become not operational. */
240 if (!sch->schib.pmcw.dnv) 237 if (!sch->schib.pmcw.dnv)
241 state = DEV_STATE_NOT_OPER; 238 state = DEV_STATE_NOT_OPER;
@@ -455,8 +452,8 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
455 return; 452 return;
456 } 453 }
457 /* Start Path Group verification. */ 454 /* Start Path Group verification. */
458 sch->vpm = 0; /* Start with no path groups set. */
459 cdev->private->state = DEV_STATE_VERIFY; 455 cdev->private->state = DEV_STATE_VERIFY;
456 cdev->private->flags.doverify = 0;
460 ccw_device_verify_start(cdev); 457 ccw_device_verify_start(cdev);
461} 458}
462 459
@@ -556,7 +553,19 @@ ccw_device_nopath_notify(void *data)
556void 553void
557ccw_device_verify_done(struct ccw_device *cdev, int err) 554ccw_device_verify_done(struct ccw_device *cdev, int err)
558{ 555{
559 cdev->private->flags.doverify = 0; 556 struct subchannel *sch;
557
558 sch = to_subchannel(cdev->dev.parent);
559 /* Update schib - pom may have changed. */
560 stsch(sch->schid, &sch->schib);
561 /* Update lpm with verified path mask. */
562 sch->lpm = sch->vpm;
563 /* Repeat path verification? */
564 if (cdev->private->flags.doverify) {
565 cdev->private->flags.doverify = 0;
566 ccw_device_verify_start(cdev);
567 return;
568 }
560 switch (err) { 569 switch (err) {
561 case -EOPNOTSUPP: /* path grouping not supported, just set online. */ 570 case -EOPNOTSUPP: /* path grouping not supported, just set online. */
562 cdev->private->options.pgroup = 0; 571 cdev->private->options.pgroup = 0;
@@ -614,6 +623,7 @@ ccw_device_online(struct ccw_device *cdev)
614 if (!cdev->private->options.pgroup) { 623 if (!cdev->private->options.pgroup) {
615 /* Start initial path verification. */ 624 /* Start initial path verification. */
616 cdev->private->state = DEV_STATE_VERIFY; 625 cdev->private->state = DEV_STATE_VERIFY;
626 cdev->private->flags.doverify = 0;
617 ccw_device_verify_start(cdev); 627 ccw_device_verify_start(cdev);
618 return 0; 628 return 0;
619 } 629 }
@@ -660,7 +670,6 @@ ccw_device_offline(struct ccw_device *cdev)
660 /* Are we doing path grouping? */ 670 /* Are we doing path grouping? */
661 if (!cdev->private->options.pgroup) { 671 if (!cdev->private->options.pgroup) {
662 /* No, set state offline immediately. */ 672 /* No, set state offline immediately. */
663 sch->vpm = 0;
664 ccw_device_done(cdev, DEV_STATE_OFFLINE); 673 ccw_device_done(cdev, DEV_STATE_OFFLINE);
665 return 0; 674 return 0;
666 } 675 }
@@ -781,6 +790,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
781 } 790 }
782 /* Device is idle, we can do the path verification. */ 791 /* Device is idle, we can do the path verification. */
783 cdev->private->state = DEV_STATE_VERIFY; 792 cdev->private->state = DEV_STATE_VERIFY;
793 cdev->private->flags.doverify = 0;
784 ccw_device_verify_start(cdev); 794 ccw_device_verify_start(cdev);
785} 795}
786 796
@@ -1043,9 +1053,9 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
1043} 1053}
1044 1054
1045static void 1055static void
1046ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event) 1056ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event)
1047{ 1057{
1048 /* When the I/O has terminated, we have to start verification. */ 1058 /* Start verification after current task finished. */
1049 cdev->private->flags.doverify = 1; 1059 cdev->private->flags.doverify = 1;
1050} 1060}
1051 1061
@@ -1111,10 +1121,7 @@ device_trigger_reprobe(struct subchannel *sch)
1111 * The pim, pam, pom values may not be accurate, but they are the best 1121 * The pim, pam, pom values may not be accurate, but they are the best
1112 * we have before performing device selection :/ 1122 * we have before performing device selection :/
1113 */ 1123 */
1114 sch->lpm = sch->schib.pmcw.pim & 1124 sch->lpm = sch->schib.pmcw.pam & sch->opm;
1115 sch->schib.pmcw.pam &
1116 sch->schib.pmcw.pom &
1117 sch->opm;
1118 /* Re-set some bits in the pmcw that were lost. */ 1125 /* Re-set some bits in the pmcw that were lost. */
1119 sch->schib.pmcw.isc = 3; 1126 sch->schib.pmcw.isc = 3;
1120 sch->schib.pmcw.csense = 1; 1127 sch->schib.pmcw.csense = 1;
@@ -1238,7 +1245,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
1238 [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, 1245 [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
1239 [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq, 1246 [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
1240 [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, 1247 [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
1241 [DEV_EVENT_VERIFY] = ccw_device_nop, 1248 [DEV_EVENT_VERIFY] = ccw_device_delay_verify,
1242 }, 1249 },
1243 [DEV_STATE_ONLINE] = { 1250 [DEV_STATE_ONLINE] = {
1244 [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, 1251 [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
@@ -1281,7 +1288,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
1281 [DEV_EVENT_NOTOPER] = ccw_device_online_notoper, 1288 [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
1282 [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq, 1289 [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq,
1283 [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout, 1290 [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout,
1284 [DEV_EVENT_VERIFY] = ccw_device_wait4io_verify, 1291 [DEV_EVENT_VERIFY] = ccw_device_delay_verify,
1285 }, 1292 },
1286 [DEV_STATE_QUIESCE] = { 1293 [DEV_STATE_QUIESCE] = {
1287 [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done, 1294 [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done,
@@ -1294,7 +1301,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
1294 [DEV_EVENT_NOTOPER] = ccw_device_nop, 1301 [DEV_EVENT_NOTOPER] = ccw_device_nop,
1295 [DEV_EVENT_INTERRUPT] = ccw_device_start_id, 1302 [DEV_EVENT_INTERRUPT] = ccw_device_start_id,
1296 [DEV_EVENT_TIMEOUT] = ccw_device_bug, 1303 [DEV_EVENT_TIMEOUT] = ccw_device_bug,
1297 [DEV_EVENT_VERIFY] = ccw_device_nop, 1304 [DEV_EVENT_VERIFY] = ccw_device_start_id,
1298 }, 1305 },
1299 [DEV_STATE_DISCONNECTED_SENSE_ID] = { 1306 [DEV_STATE_DISCONNECTED_SENSE_ID] = {
1300 [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper, 1307 [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper,
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index acad8f852eda..93a897eebfff 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -256,7 +256,7 @@ ccw_device_get_path_mask(struct ccw_device *cdev)
256 if (!sch) 256 if (!sch)
257 return 0; 257 return 0;
258 else 258 else
259 return sch->vpm; 259 return sch->lpm;
260} 260}
261 261
262static void 262static void
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 1693a102dcfe..8ca2d078848c 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -245,18 +245,17 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
245 memset(&cdev->private->irb, 0, sizeof(struct irb)); 245 memset(&cdev->private->irb, 0, sizeof(struct irb));
246 246
247 /* Try multiple times. */ 247 /* Try multiple times. */
248 ret = -ENODEV; 248 ret = -EACCES;
249 if (cdev->private->iretry > 0) { 249 if (cdev->private->iretry > 0) {
250 cdev->private->iretry--; 250 cdev->private->iretry--;
251 ret = cio_start (sch, cdev->private->iccws, 251 ret = cio_start (sch, cdev->private->iccws,
252 cdev->private->imask); 252 cdev->private->imask);
253 /* ret is 0, -EBUSY, -EACCES or -ENODEV */ 253 /* We expect an interrupt in case of success or busy
254 if ((ret != -EACCES) && (ret != -ENODEV)) 254 * indication. */
255 if ((ret == 0) || (ret == -EBUSY))
255 return ret; 256 return ret;
256 } 257 }
257 /* PGID command failed on this path. Switch it off. */ 258 /* PGID command failed on this path. */
258 sch->lpm &= ~cdev->private->imask;
259 sch->vpm &= ~cdev->private->imask;
260 CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " 259 CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
261 "0.%x.%04x, lpm %02X, became 'not operational'\n", 260 "0.%x.%04x, lpm %02X, became 'not operational'\n",
262 cdev->private->devno, sch->schid.ssid, 261 cdev->private->devno, sch->schid.ssid,
@@ -286,18 +285,17 @@ static int __ccw_device_do_nop(struct ccw_device *cdev)
286 memset(&cdev->private->irb, 0, sizeof(struct irb)); 285 memset(&cdev->private->irb, 0, sizeof(struct irb));
287 286
288 /* Try multiple times. */ 287 /* Try multiple times. */
289 ret = -ENODEV; 288 ret = -EACCES;
290 if (cdev->private->iretry > 0) { 289 if (cdev->private->iretry > 0) {
291 cdev->private->iretry--; 290 cdev->private->iretry--;
292 ret = cio_start (sch, cdev->private->iccws, 291 ret = cio_start (sch, cdev->private->iccws,
293 cdev->private->imask); 292 cdev->private->imask);
294 /* ret is 0, -EBUSY, -EACCES or -ENODEV */ 293 /* We expect an interrupt in case of success or busy
295 if ((ret != -EACCES) && (ret != -ENODEV)) 294 * indication. */
295 if ((ret == 0) || (ret == -EBUSY))
296 return ret; 296 return ret;
297 } 297 }
298 /* nop command failed on this path. Switch it off. */ 298 /* nop command failed on this path. */
299 sch->lpm &= ~cdev->private->imask;
300 sch->vpm &= ~cdev->private->imask;
301 CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel " 299 CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
302 "0.%x.%04x, lpm %02X, became 'not operational'\n", 300 "0.%x.%04x, lpm %02X, became 'not operational'\n",
303 cdev->private->devno, sch->schid.ssid, 301 cdev->private->devno, sch->schid.ssid,
@@ -372,27 +370,32 @@ static void
372__ccw_device_verify_start(struct ccw_device *cdev) 370__ccw_device_verify_start(struct ccw_device *cdev)
373{ 371{
374 struct subchannel *sch; 372 struct subchannel *sch;
375 __u8 imask, func; 373 __u8 func;
376 int ret; 374 int ret;
377 375
378 sch = to_subchannel(cdev->dev.parent); 376 sch = to_subchannel(cdev->dev.parent);
379 while (sch->vpm != sch->lpm) { 377 /* Repeat for all paths. */
380 /* Find first unequal bit in vpm vs. lpm */ 378 for (; cdev->private->imask; cdev->private->imask >>= 1,
381 for (imask = 0x80; imask != 0; imask >>= 1) 379 cdev->private->iretry = 5) {
382 if ((sch->vpm & imask) != (sch->lpm & imask)) 380 if ((cdev->private->imask & sch->schib.pmcw.pam) == 0)
383 break; 381 /* Path not available, try next. */
384 cdev->private->imask = imask; 382 continue;
385 if (cdev->private->options.pgroup) { 383 if (cdev->private->options.pgroup) {
386 func = (sch->vpm & imask) ? 384 if (sch->opm & cdev->private->imask)
387 SPID_FUNC_RESIGN : SPID_FUNC_ESTABLISH; 385 func = SPID_FUNC_ESTABLISH;
386 else
387 func = SPID_FUNC_RESIGN;
388 ret = __ccw_device_do_pgid(cdev, func); 388 ret = __ccw_device_do_pgid(cdev, func);
389 } else 389 } else
390 ret = __ccw_device_do_nop(cdev); 390 ret = __ccw_device_do_nop(cdev);
391 /* We expect an interrupt in case of success or busy
392 * indication. */
391 if (ret == 0 || ret == -EBUSY) 393 if (ret == 0 || ret == -EBUSY)
392 return; 394 return;
393 cdev->private->iretry = 5; 395 /* Permanent path failure, try next. */
394 } 396 }
395 ccw_device_verify_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV); 397 /* Done with all paths. */
398 ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);
396} 399}
397 400
398/* 401/*
@@ -421,14 +424,14 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
421 else 424 else
422 ret = __ccw_device_check_nop(cdev); 425 ret = __ccw_device_check_nop(cdev);
423 memset(&cdev->private->irb, 0, sizeof(struct irb)); 426 memset(&cdev->private->irb, 0, sizeof(struct irb));
427
424 switch (ret) { 428 switch (ret) {
425 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */ 429 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
426 case 0: 430 case 0:
427 /* Establish or Resign Path Group done. Update vpm. */ 431 /* Path verification ccw finished successfully, update lpm. */
428 if ((sch->lpm & cdev->private->imask) != 0) 432 sch->vpm |= sch->opm & cdev->private->imask;
429 sch->vpm |= cdev->private->imask; 433 /* Go on with next path. */
430 else 434 cdev->private->imask >>= 1;
431 sch->vpm &= ~cdev->private->imask;
432 cdev->private->iretry = 5; 435 cdev->private->iretry = 5;
433 __ccw_device_verify_start(cdev); 436 __ccw_device_verify_start(cdev);
434 break; 437 break;
@@ -441,6 +444,10 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
441 cdev->private->options.pgroup = 0; 444 cdev->private->options.pgroup = 0;
442 else 445 else
443 cdev->private->flags.pgid_single = 1; 446 cdev->private->flags.pgid_single = 1;
447 /* Retry */
448 sch->vpm = 0;
449 cdev->private->imask = 0x80;
450 cdev->private->iretry = 5;
444 /* fall through. */ 451 /* fall through. */
445 case -EAGAIN: /* Try again. */ 452 case -EAGAIN: /* Try again. */
446 __ccw_device_verify_start(cdev); 453 __ccw_device_verify_start(cdev);
@@ -449,8 +456,7 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
449 ccw_device_verify_done(cdev, -ETIME); 456 ccw_device_verify_done(cdev, -ETIME);
450 break; 457 break;
451 case -EACCES: /* channel is not operational. */ 458 case -EACCES: /* channel is not operational. */
452 sch->lpm &= ~cdev->private->imask; 459 cdev->private->imask >>= 1;
453 sch->vpm &= ~cdev->private->imask;
454 cdev->private->iretry = 5; 460 cdev->private->iretry = 5;
455 __ccw_device_verify_start(cdev); 461 __ccw_device_verify_start(cdev);
456 break; 462 break;
@@ -463,19 +469,17 @@ ccw_device_verify_start(struct ccw_device *cdev)
463 struct subchannel *sch = to_subchannel(cdev->dev.parent); 469 struct subchannel *sch = to_subchannel(cdev->dev.parent);
464 470
465 cdev->private->flags.pgid_single = 0; 471 cdev->private->flags.pgid_single = 0;
472 cdev->private->imask = 0x80;
466 cdev->private->iretry = 5; 473 cdev->private->iretry = 5;
467 /* 474
468 * Update sch->lpm with current values to catch paths becoming 475 /* Start with empty vpm. */
469 * available again. 476 sch->vpm = 0;
470 */ 477
478 /* Get current pam. */
471 if (stsch(sch->schid, &sch->schib)) { 479 if (stsch(sch->schid, &sch->schib)) {
472 ccw_device_verify_done(cdev, -ENODEV); 480 ccw_device_verify_done(cdev, -ENODEV);
473 return; 481 return;
474 } 482 }
475 sch->lpm = sch->schib.pmcw.pim &
476 sch->schib.pmcw.pam &
477 sch->schib.pmcw.pom &
478 sch->opm;
479 __ccw_device_verify_start(cdev); 483 __ccw_device_verify_start(cdev);
480} 484}
481 485
@@ -524,7 +528,6 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
524 switch (ret) { 528 switch (ret) {
525 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */ 529 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
526 case 0: /* disband successful. */ 530 case 0: /* disband successful. */
527 sch->vpm = 0;
528 ccw_device_disband_done(cdev, ret); 531 ccw_device_disband_done(cdev, ret);
529 break; 532 break;
530 case -EOPNOTSUPP: 533 case -EOPNOTSUPP: