diff options
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 88 |
1 files changed, 70 insertions, 18 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index cb1af0b6f033..7a39e0b0386c 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -152,7 +152,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) | |||
152 | if (cdev->private->iretry) { | 152 | if (cdev->private->iretry) { |
153 | cdev->private->iretry--; | 153 | cdev->private->iretry--; |
154 | ret = cio_halt(sch); | 154 | ret = cio_halt(sch); |
155 | return (ret == 0) ? -EBUSY : ret; | 155 | if (ret != -EBUSY) |
156 | return (ret == 0) ? -EBUSY : ret; | ||
156 | } | 157 | } |
157 | /* halt io unsuccessful. */ | 158 | /* halt io unsuccessful. */ |
158 | cdev->private->iretry = 255; /* 255 clear retries. */ | 159 | cdev->private->iretry = 255; /* 255 clear retries. */ |
@@ -378,6 +379,56 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
378 | put_device (&cdev->dev); | 379 | put_device (&cdev->dev); |
379 | } | 380 | } |
380 | 381 | ||
382 | static inline int cmp_pgid(struct pgid *p1, struct pgid *p2) | ||
383 | { | ||
384 | char *c1; | ||
385 | char *c2; | ||
386 | |||
387 | c1 = (char *)p1; | ||
388 | c2 = (char *)p2; | ||
389 | |||
390 | return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1); | ||
391 | } | ||
392 | |||
393 | static void __ccw_device_get_common_pgid(struct ccw_device *cdev) | ||
394 | { | ||
395 | int i; | ||
396 | int last; | ||
397 | |||
398 | last = 0; | ||
399 | for (i = 0; i < 8; i++) { | ||
400 | if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET) | ||
401 | /* No PGID yet */ | ||
402 | continue; | ||
403 | if (cdev->private->pgid[last].inf.ps.state1 == | ||
404 | SNID_STATE1_RESET) { | ||
405 | /* First non-zero PGID */ | ||
406 | last = i; | ||
407 | continue; | ||
408 | } | ||
409 | if (cmp_pgid(&cdev->private->pgid[i], | ||
410 | &cdev->private->pgid[last]) == 0) | ||
411 | /* Non-conflicting PGIDs */ | ||
412 | continue; | ||
413 | |||
414 | /* PGID mismatch, can't pathgroup. */ | ||
415 | CIO_MSG_EVENT(0, "SNID - pgid mismatch for device " | ||
416 | "0.%x.%04x, can't pathgroup\n", | ||
417 | cdev->private->ssid, cdev->private->devno); | ||
418 | cdev->private->options.pgroup = 0; | ||
419 | return; | ||
420 | } | ||
421 | if (cdev->private->pgid[last].inf.ps.state1 == | ||
422 | SNID_STATE1_RESET) | ||
423 | /* No previous pgid found */ | ||
424 | memcpy(&cdev->private->pgid[0], &css[0]->global_pgid, | ||
425 | sizeof(struct pgid)); | ||
426 | else | ||
427 | /* Use existing pgid */ | ||
428 | memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last], | ||
429 | sizeof(struct pgid)); | ||
430 | } | ||
431 | |||
381 | /* | 432 | /* |
382 | * Function called from device_pgid.c after sense path ground has completed. | 433 | * Function called from device_pgid.c after sense path ground has completed. |
383 | */ | 434 | */ |
@@ -388,24 +439,26 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err) | |||
388 | 439 | ||
389 | sch = to_subchannel(cdev->dev.parent); | 440 | sch = to_subchannel(cdev->dev.parent); |
390 | switch (err) { | 441 | switch (err) { |
391 | case 0: | 442 | case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */ |
392 | /* Start Path Group verification. */ | 443 | cdev->private->options.pgroup = 0; |
393 | sch->vpm = 0; /* Start with no path groups set. */ | 444 | break; |
394 | cdev->private->state = DEV_STATE_VERIFY; | 445 | case 0: /* success */ |
395 | ccw_device_verify_start(cdev); | 446 | case -EACCES: /* partial success, some paths not operational */ |
447 | /* Check if all pgids are equal or 0. */ | ||
448 | __ccw_device_get_common_pgid(cdev); | ||
396 | break; | 449 | break; |
397 | case -ETIME: /* Sense path group id stopped by timeout. */ | 450 | case -ETIME: /* Sense path group id stopped by timeout. */ |
398 | case -EUSERS: /* device is reserved for someone else. */ | 451 | case -EUSERS: /* device is reserved for someone else. */ |
399 | ccw_device_done(cdev, DEV_STATE_BOXED); | 452 | ccw_device_done(cdev, DEV_STATE_BOXED); |
400 | break; | 453 | return; |
401 | case -EOPNOTSUPP: /* path grouping not supported, just set online. */ | ||
402 | cdev->private->options.pgroup = 0; | ||
403 | ccw_device_done(cdev, DEV_STATE_ONLINE); | ||
404 | break; | ||
405 | default: | 454 | default: |
406 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | 455 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); |
407 | break; | 456 | return; |
408 | } | 457 | } |
458 | /* Start Path Group verification. */ | ||
459 | sch->vpm = 0; /* Start with no path groups set. */ | ||
460 | cdev->private->state = DEV_STATE_VERIFY; | ||
461 | ccw_device_verify_start(cdev); | ||
409 | } | 462 | } |
410 | 463 | ||
411 | /* | 464 | /* |
@@ -562,8 +615,9 @@ ccw_device_online(struct ccw_device *cdev) | |||
562 | } | 615 | } |
563 | /* Do we want to do path grouping? */ | 616 | /* Do we want to do path grouping? */ |
564 | if (!cdev->private->options.pgroup) { | 617 | if (!cdev->private->options.pgroup) { |
565 | /* No, set state online immediately. */ | 618 | /* Start initial path verification. */ |
566 | ccw_device_done(cdev, DEV_STATE_ONLINE); | 619 | cdev->private->state = DEV_STATE_VERIFY; |
620 | ccw_device_verify_start(cdev); | ||
567 | return 0; | 621 | return 0; |
568 | } | 622 | } |
569 | /* Do a SensePGID first. */ | 623 | /* Do a SensePGID first. */ |
@@ -609,6 +663,7 @@ ccw_device_offline(struct ccw_device *cdev) | |||
609 | /* Are we doing path grouping? */ | 663 | /* Are we doing path grouping? */ |
610 | if (!cdev->private->options.pgroup) { | 664 | if (!cdev->private->options.pgroup) { |
611 | /* No, set state offline immediately. */ | 665 | /* No, set state offline immediately. */ |
666 | sch->vpm = 0; | ||
612 | ccw_device_done(cdev, DEV_STATE_OFFLINE); | 667 | ccw_device_done(cdev, DEV_STATE_OFFLINE); |
613 | return 0; | 668 | return 0; |
614 | } | 669 | } |
@@ -705,8 +760,6 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) | |||
705 | { | 760 | { |
706 | struct subchannel *sch; | 761 | struct subchannel *sch; |
707 | 762 | ||
708 | if (!cdev->private->options.pgroup) | ||
709 | return; | ||
710 | if (cdev->private->state == DEV_STATE_W4SENSE) { | 763 | if (cdev->private->state == DEV_STATE_W4SENSE) { |
711 | cdev->private->flags.doverify = 1; | 764 | cdev->private->flags.doverify = 1; |
712 | return; | 765 | return; |
@@ -995,8 +1048,7 @@ static void | |||
995 | ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event) | 1048 | ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event) |
996 | { | 1049 | { |
997 | /* When the I/O has terminated, we have to start verification. */ | 1050 | /* When the I/O has terminated, we have to start verification. */ |
998 | if (cdev->private->options.pgroup) | 1051 | cdev->private->flags.doverify = 1; |
999 | cdev->private->flags.doverify = 1; | ||
1000 | } | 1052 | } |
1001 | 1053 | ||
1002 | static void | 1054 | static void |