diff options
Diffstat (limited to 'drivers/s390/cio/chsc.c')
| -rw-r--r-- | drivers/s390/cio/chsc.c | 82 |
1 files changed, 36 insertions, 46 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 2d78f0f4a40f..dbfb77b03928 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
| @@ -251,6 +251,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) | |||
| 251 | cc = cio_clear(sch); | 251 | cc = cio_clear(sch); |
| 252 | if (cc == -ENODEV) | 252 | if (cc == -ENODEV) |
| 253 | goto out_unreg; | 253 | goto out_unreg; |
| 254 | /* Request retry of internal operation. */ | ||
| 255 | device_set_intretry(sch); | ||
| 254 | /* Call handler. */ | 256 | /* Call handler. */ |
| 255 | if (sch->driver && sch->driver->termination) | 257 | if (sch->driver && sch->driver->termination) |
| 256 | sch->driver->termination(&sch->dev); | 258 | sch->driver->termination(&sch->dev); |
| @@ -711,9 +713,6 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
| 711 | { | 713 | { |
| 712 | int cc; | 714 | int cc; |
| 713 | 715 | ||
| 714 | if (!device_is_online(sch)) | ||
| 715 | /* cio could be doing I/O. */ | ||
| 716 | return 0; | ||
| 717 | cc = stsch(sch->schid, &sch->schib); | 716 | cc = stsch(sch->schid, &sch->schib); |
| 718 | if (cc) | 717 | if (cc) |
| 719 | return 0; | 718 | return 0; |
| @@ -722,6 +721,26 @@ static inline int check_for_io_on_path(struct subchannel *sch, int index) | |||
| 722 | return 0; | 721 | return 0; |
| 723 | } | 722 | } |
| 724 | 723 | ||
| 724 | static void terminate_internal_io(struct subchannel *sch) | ||
| 725 | { | ||
| 726 | if (cio_clear(sch)) { | ||
| 727 | /* Recheck device in case clear failed. */ | ||
| 728 | sch->lpm = 0; | ||
| 729 | if (device_trigger_verify(sch) != 0) { | ||
| 730 | if(css_enqueue_subchannel_slow(sch->schid)) { | ||
| 731 | css_clear_subchannel_slow_list(); | ||
| 732 | need_rescan = 1; | ||
| 733 | } | ||
| 734 | } | ||
| 735 | return; | ||
| 736 | } | ||
| 737 | /* Request retry of internal operation. */ | ||
| 738 | device_set_intretry(sch); | ||
| 739 | /* Call handler. */ | ||
| 740 | if (sch->driver && sch->driver->termination) | ||
| 741 | sch->driver->termination(&sch->dev); | ||
| 742 | } | ||
| 743 | |||
| 725 | static inline void | 744 | static inline void |
| 726 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | 745 | __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) |
| 727 | { | 746 | { |
| @@ -744,20 +763,26 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) | |||
| 744 | device_trigger_reprobe(sch); | 763 | device_trigger_reprobe(sch); |
| 745 | else if (sch->driver && sch->driver->verify) | 764 | else if (sch->driver && sch->driver->verify) |
| 746 | sch->driver->verify(&sch->dev); | 765 | sch->driver->verify(&sch->dev); |
| 747 | } else { | 766 | break; |
| 748 | sch->opm &= ~(0x80 >> chp); | 767 | } |
| 749 | sch->lpm &= ~(0x80 >> chp); | 768 | sch->opm &= ~(0x80 >> chp); |
| 750 | if (check_for_io_on_path(sch, chp)) | 769 | sch->lpm &= ~(0x80 >> chp); |
| 770 | if (check_for_io_on_path(sch, chp)) { | ||
| 771 | if (device_is_online(sch)) | ||
| 751 | /* Path verification is done after killing. */ | 772 | /* Path verification is done after killing. */ |
| 752 | device_kill_io(sch); | 773 | device_kill_io(sch); |
| 753 | else if (!sch->lpm) { | 774 | else |
| 775 | /* Kill and retry internal I/O. */ | ||
| 776 | terminate_internal_io(sch); | ||
| 777 | } else if (!sch->lpm) { | ||
| 778 | if (device_trigger_verify(sch) != 0) { | ||
| 754 | if (css_enqueue_subchannel_slow(sch->schid)) { | 779 | if (css_enqueue_subchannel_slow(sch->schid)) { |
| 755 | css_clear_subchannel_slow_list(); | 780 | css_clear_subchannel_slow_list(); |
| 756 | need_rescan = 1; | 781 | need_rescan = 1; |
| 757 | } | 782 | } |
| 758 | } else if (sch->driver && sch->driver->verify) | 783 | } |
| 759 | sch->driver->verify(&sch->dev); | 784 | } else if (sch->driver && sch->driver->verify) |
| 760 | } | 785 | sch->driver->verify(&sch->dev); |
| 761 | break; | 786 | break; |
| 762 | } | 787 | } |
| 763 | spin_unlock_irqrestore(&sch->lock, flags); | 788 | spin_unlock_irqrestore(&sch->lock, flags); |
| @@ -1465,41 +1490,6 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no) | |||
| 1465 | return desc; | 1490 | return desc; |
| 1466 | } | 1491 | } |
| 1467 | 1492 | ||
| 1468 | static int reset_channel_path(struct channel_path *chp) | ||
| 1469 | { | ||
| 1470 | int cc; | ||
| 1471 | |||
| 1472 | cc = rchp(chp->id); | ||
| 1473 | switch (cc) { | ||
| 1474 | case 0: | ||
| 1475 | return 0; | ||
| 1476 | case 2: | ||
| 1477 | return -EBUSY; | ||
| 1478 | default: | ||
| 1479 | return -ENODEV; | ||
| 1480 | } | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | static void reset_channel_paths_css(struct channel_subsystem *css) | ||
| 1484 | { | ||
| 1485 | int i; | ||
| 1486 | |||
| 1487 | for (i = 0; i <= __MAX_CHPID; i++) { | ||
| 1488 | if (css->chps[i]) | ||
| 1489 | reset_channel_path(css->chps[i]); | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | void cio_reset_channel_paths(void) | ||
| 1494 | { | ||
| 1495 | int i; | ||
| 1496 | |||
| 1497 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
| 1498 | if (css[i] && css[i]->valid) | ||
| 1499 | reset_channel_paths_css(css[i]); | ||
| 1500 | } | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | static int __init | 1493 | static int __init |
| 1504 | chsc_alloc_sei_area(void) | 1494 | chsc_alloc_sei_area(void) |
| 1505 | { | 1495 | { |
