diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/chsc.c | 82 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 128 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 3 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 17 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 27 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 10 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 30 | ||||
-rw-r--r-- | drivers/s390/cio/device_status.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.c | 8 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 4 |
10 files changed, 226 insertions, 86 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 | { |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 8936e460a807..20aee2783847 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
22 | #include <asm/irq_regs.h> | 22 | #include <asm/irq_regs.h> |
23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
24 | #include <asm/reset.h> | ||
24 | #include "airq.h" | 25 | #include "airq.h" |
25 | #include "cio.h" | 26 | #include "cio.h" |
26 | #include "css.h" | 27 | #include "css.h" |
@@ -28,6 +29,7 @@ | |||
28 | #include "ioasm.h" | 29 | #include "ioasm.h" |
29 | #include "blacklist.h" | 30 | #include "blacklist.h" |
30 | #include "cio_debug.h" | 31 | #include "cio_debug.h" |
32 | #include "../s390mach.h" | ||
31 | 33 | ||
32 | debug_info_t *cio_debug_msg_id; | 34 | debug_info_t *cio_debug_msg_id; |
33 | debug_info_t *cio_debug_trace_id; | 35 | debug_info_t *cio_debug_trace_id; |
@@ -841,26 +843,12 @@ __clear_subchannel_easy(struct subchannel_id schid) | |||
841 | return -EBUSY; | 843 | return -EBUSY; |
842 | } | 844 | } |
843 | 845 | ||
844 | struct sch_match_id { | 846 | static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) |
845 | struct subchannel_id schid; | ||
846 | struct ccw_dev_id devid; | ||
847 | int rc; | ||
848 | }; | ||
849 | |||
850 | static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, | ||
851 | void *data) | ||
852 | { | 847 | { |
853 | struct schib schib; | 848 | struct schib schib; |
854 | struct sch_match_id *match_id = data; | ||
855 | 849 | ||
856 | if (stsch_err(schid, &schib)) | 850 | if (stsch_err(schid, &schib)) |
857 | return -ENXIO; | 851 | return -ENXIO; |
858 | if (match_id && schib.pmcw.dnv && | ||
859 | (schib.pmcw.dev == match_id->devid.devno) && | ||
860 | (schid.ssid == match_id->devid.ssid)) { | ||
861 | match_id->schid = schid; | ||
862 | match_id->rc = 0; | ||
863 | } | ||
864 | if (!schib.pmcw.ena) | 852 | if (!schib.pmcw.ena) |
865 | return 0; | 853 | return 0; |
866 | switch(__disable_subchannel_easy(schid, &schib)) { | 854 | switch(__disable_subchannel_easy(schid, &schib)) { |
@@ -876,27 +864,111 @@ static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid, | |||
876 | return 0; | 864 | return 0; |
877 | } | 865 | } |
878 | 866 | ||
879 | static int clear_all_subchannels_and_match(struct ccw_dev_id *devid, | 867 | static atomic_t chpid_reset_count; |
880 | struct subchannel_id *schid) | 868 | |
869 | static void s390_reset_chpids_mcck_handler(void) | ||
870 | { | ||
871 | struct crw crw; | ||
872 | struct mci *mci; | ||
873 | |||
874 | /* Check for pending channel report word. */ | ||
875 | mci = (struct mci *)&S390_lowcore.mcck_interruption_code; | ||
876 | if (!mci->cp) | ||
877 | return; | ||
878 | /* Process channel report words. */ | ||
879 | while (stcrw(&crw) == 0) { | ||
880 | /* Check for responses to RCHP. */ | ||
881 | if (crw.slct && crw.rsc == CRW_RSC_CPATH) | ||
882 | atomic_dec(&chpid_reset_count); | ||
883 | } | ||
884 | } | ||
885 | |||
886 | #define RCHP_TIMEOUT (30 * USEC_PER_SEC) | ||
887 | static void css_reset(void) | ||
888 | { | ||
889 | int i, ret; | ||
890 | unsigned long long timeout; | ||
891 | |||
892 | /* Reset subchannels. */ | ||
893 | for_each_subchannel(__shutdown_subchannel_easy, NULL); | ||
894 | /* Reset channel paths. */ | ||
895 | s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; | ||
896 | /* Enable channel report machine checks. */ | ||
897 | __ctl_set_bit(14, 28); | ||
898 | /* Temporarily reenable machine checks. */ | ||
899 | local_mcck_enable(); | ||
900 | for (i = 0; i <= __MAX_CHPID; i++) { | ||
901 | ret = rchp(i); | ||
902 | if ((ret == 0) || (ret == 2)) | ||
903 | /* | ||
904 | * rchp either succeeded, or another rchp is already | ||
905 | * in progress. In either case, we'll get a crw. | ||
906 | */ | ||
907 | atomic_inc(&chpid_reset_count); | ||
908 | } | ||
909 | /* Wait for machine check for all channel paths. */ | ||
910 | timeout = get_clock() + (RCHP_TIMEOUT << 12); | ||
911 | while (atomic_read(&chpid_reset_count) != 0) { | ||
912 | if (get_clock() > timeout) | ||
913 | break; | ||
914 | cpu_relax(); | ||
915 | } | ||
916 | /* Disable machine checks again. */ | ||
917 | local_mcck_disable(); | ||
918 | /* Disable channel report machine checks. */ | ||
919 | __ctl_clear_bit(14, 28); | ||
920 | s390_reset_mcck_handler = NULL; | ||
921 | } | ||
922 | |||
923 | static struct reset_call css_reset_call = { | ||
924 | .fn = css_reset, | ||
925 | }; | ||
926 | |||
927 | static int __init init_css_reset_call(void) | ||
928 | { | ||
929 | atomic_set(&chpid_reset_count, 0); | ||
930 | register_reset_call(&css_reset_call); | ||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | arch_initcall(init_css_reset_call); | ||
935 | |||
936 | struct sch_match_id { | ||
937 | struct subchannel_id schid; | ||
938 | struct ccw_dev_id devid; | ||
939 | int rc; | ||
940 | }; | ||
941 | |||
942 | static int __reipl_subchannel_match(struct subchannel_id schid, void *data) | ||
943 | { | ||
944 | struct schib schib; | ||
945 | struct sch_match_id *match_id = data; | ||
946 | |||
947 | if (stsch_err(schid, &schib)) | ||
948 | return -ENXIO; | ||
949 | if (schib.pmcw.dnv && | ||
950 | (schib.pmcw.dev == match_id->devid.devno) && | ||
951 | (schid.ssid == match_id->devid.ssid)) { | ||
952 | match_id->schid = schid; | ||
953 | match_id->rc = 0; | ||
954 | return 1; | ||
955 | } | ||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | static int reipl_find_schid(struct ccw_dev_id *devid, | ||
960 | struct subchannel_id *schid) | ||
881 | { | 961 | { |
882 | struct sch_match_id match_id; | 962 | struct sch_match_id match_id; |
883 | 963 | ||
884 | match_id.devid = *devid; | 964 | match_id.devid = *devid; |
885 | match_id.rc = -ENODEV; | 965 | match_id.rc = -ENODEV; |
886 | local_irq_disable(); | 966 | for_each_subchannel(__reipl_subchannel_match, &match_id); |
887 | for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id); | ||
888 | if (match_id.rc == 0) | 967 | if (match_id.rc == 0) |
889 | *schid = match_id.schid; | 968 | *schid = match_id.schid; |
890 | return match_id.rc; | 969 | return match_id.rc; |
891 | } | 970 | } |
892 | 971 | ||
893 | |||
894 | void clear_all_subchannels(void) | ||
895 | { | ||
896 | local_irq_disable(); | ||
897 | for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL); | ||
898 | } | ||
899 | |||
900 | extern void do_reipl_asm(__u32 schid); | 972 | extern void do_reipl_asm(__u32 schid); |
901 | 973 | ||
902 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ | 974 | /* Make sure all subchannels are quiet before we re-ipl an lpar. */ |
@@ -904,9 +976,9 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) | |||
904 | { | 976 | { |
905 | struct subchannel_id schid; | 977 | struct subchannel_id schid; |
906 | 978 | ||
907 | if (clear_all_subchannels_and_match(devid, &schid)) | 979 | s390_reset_system(); |
980 | if (reipl_find_schid(devid, &schid) != 0) | ||
908 | panic("IPL Device not found\n"); | 981 | panic("IPL Device not found\n"); |
909 | cio_reset_channel_paths(); | ||
910 | do_reipl_asm(*((__u32*)&schid)); | 982 | do_reipl_asm(*((__u32*)&schid)); |
911 | } | 983 | } |
912 | 984 | ||
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 4c2ff8336288..9ff064e71767 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -94,6 +94,7 @@ struct ccw_device_private { | |||
94 | unsigned int donotify:1; /* call notify function */ | 94 | unsigned int donotify:1; /* call notify function */ |
95 | unsigned int recog_done:1; /* dev. recog. complete */ | 95 | unsigned int recog_done:1; /* dev. recog. complete */ |
96 | unsigned int fake_irb:1; /* deliver faked irb */ | 96 | unsigned int fake_irb:1; /* deliver faked irb */ |
97 | unsigned int intretry:1; /* retry internal operation */ | ||
97 | } __attribute__((packed)) flags; | 98 | } __attribute__((packed)) flags; |
98 | unsigned long intparm; /* user interruption parameter */ | 99 | unsigned long intparm; /* user interruption parameter */ |
99 | struct qdio_irq *qdio_data; | 100 | struct qdio_irq *qdio_data; |
@@ -171,6 +172,8 @@ void device_trigger_reprobe(struct subchannel *); | |||
171 | /* Helper functions for vary on/off. */ | 172 | /* Helper functions for vary on/off. */ |
172 | int device_is_online(struct subchannel *); | 173 | int device_is_online(struct subchannel *); |
173 | void device_kill_io(struct subchannel *); | 174 | void device_kill_io(struct subchannel *); |
175 | void device_set_intretry(struct subchannel *sch); | ||
176 | int device_trigger_verify(struct subchannel *sch); | ||
174 | 177 | ||
175 | /* Machine check helper function. */ | 178 | /* Machine check helper function. */ |
176 | void device_kill_pending_timer(struct subchannel *); | 179 | void device_kill_pending_timer(struct subchannel *); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 39c98f940507..d3d3716ff84b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -687,8 +687,20 @@ io_subchannel_register(void *data) | |||
687 | cdev = data; | 687 | cdev = data; |
688 | sch = to_subchannel(cdev->dev.parent); | 688 | sch = to_subchannel(cdev->dev.parent); |
689 | 689 | ||
690 | /* | ||
691 | * io_subchannel_register() will also be called after device | ||
692 | * recognition has been done for a boxed device (which will already | ||
693 | * be registered). We need to reprobe since we may now have sense id | ||
694 | * information. | ||
695 | */ | ||
690 | if (klist_node_attached(&cdev->dev.knode_parent)) { | 696 | if (klist_node_attached(&cdev->dev.knode_parent)) { |
691 | bus_rescan_devices(&ccw_bus_type); | 697 | if (!cdev->drv) { |
698 | ret = device_reprobe(&cdev->dev); | ||
699 | if (ret) | ||
700 | /* We can't do much here. */ | ||
701 | dev_info(&cdev->dev, "device_reprobe() returned" | ||
702 | " %d\n", ret); | ||
703 | } | ||
692 | goto out; | 704 | goto out; |
693 | } | 705 | } |
694 | /* make it known to the system */ | 706 | /* make it known to the system */ |
@@ -948,6 +960,9 @@ io_subchannel_ioterm(struct device *dev) | |||
948 | cdev = dev->driver_data; | 960 | cdev = dev->driver_data; |
949 | if (!cdev) | 961 | if (!cdev) |
950 | return; | 962 | return; |
963 | /* Internal I/O will be retried by the interrupt handler. */ | ||
964 | if (cdev->private->flags.intretry) | ||
965 | return; | ||
951 | cdev->private->state = DEV_STATE_CLEAR_VERIFY; | 966 | cdev->private->state = DEV_STATE_CLEAR_VERIFY; |
952 | if (cdev->handler) | 967 | if (cdev->handler) |
953 | cdev->handler(cdev, cdev->private->intparm, | 968 | cdev->handler(cdev, cdev->private->intparm, |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index de3d0857db9f..09c7672eb3f3 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -59,6 +59,27 @@ device_set_disconnected(struct subchannel *sch) | |||
59 | cdev->private->state = DEV_STATE_DISCONNECTED; | 59 | cdev->private->state = DEV_STATE_DISCONNECTED; |
60 | } | 60 | } |
61 | 61 | ||
62 | void device_set_intretry(struct subchannel *sch) | ||
63 | { | ||
64 | struct ccw_device *cdev; | ||
65 | |||
66 | cdev = sch->dev.driver_data; | ||
67 | if (!cdev) | ||
68 | return; | ||
69 | cdev->private->flags.intretry = 1; | ||
70 | } | ||
71 | |||
72 | int device_trigger_verify(struct subchannel *sch) | ||
73 | { | ||
74 | struct ccw_device *cdev; | ||
75 | |||
76 | cdev = sch->dev.driver_data; | ||
77 | if (!cdev || !cdev->online) | ||
78 | return -EINVAL; | ||
79 | dev_fsm_event(cdev, DEV_EVENT_VERIFY); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
62 | /* | 83 | /* |
63 | * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. | 84 | * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. |
64 | */ | 85 | */ |
@@ -893,6 +914,12 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) | |||
893 | * had killed the original request. | 914 | * had killed the original request. |
894 | */ | 915 | */ |
895 | if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { | 916 | if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { |
917 | /* Retry Basic Sense if requested. */ | ||
918 | if (cdev->private->flags.intretry) { | ||
919 | cdev->private->flags.intretry = 0; | ||
920 | ccw_device_do_sense(cdev, irb); | ||
921 | return; | ||
922 | } | ||
896 | cdev->private->flags.dosense = 0; | 923 | cdev->private->flags.dosense = 0; |
897 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | 924 | memset(&cdev->private->irb, 0, sizeof(struct irb)); |
898 | ccw_device_accumulate_irb(cdev, irb); | 925 | ccw_device_accumulate_irb(cdev, irb); |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index a74785b9e4eb..f17275917fe5 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -191,6 +191,8 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) | |||
191 | if ((sch->opm & cdev->private->imask) != 0 && | 191 | if ((sch->opm & cdev->private->imask) != 0 && |
192 | cdev->private->iretry > 0) { | 192 | cdev->private->iretry > 0) { |
193 | cdev->private->iretry--; | 193 | cdev->private->iretry--; |
194 | /* Reset internal retry indication. */ | ||
195 | cdev->private->flags.intretry = 0; | ||
194 | ret = cio_start (sch, cdev->private->iccws, | 196 | ret = cio_start (sch, cdev->private->iccws, |
195 | cdev->private->imask); | 197 | cdev->private->imask); |
196 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ | 198 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ |
@@ -237,8 +239,14 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
237 | return 0; /* Success */ | 239 | return 0; /* Success */ |
238 | } | 240 | } |
239 | /* Check the error cases. */ | 241 | /* Check the error cases. */ |
240 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 242 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
243 | /* Retry Sense ID if requested. */ | ||
244 | if (cdev->private->flags.intretry) { | ||
245 | cdev->private->flags.intretry = 0; | ||
246 | return -EAGAIN; | ||
247 | } | ||
241 | return -ETIME; | 248 | return -ETIME; |
249 | } | ||
242 | if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) { | 250 | if (irb->esw.esw0.erw.cons && (irb->ecw[0] & SNS0_CMD_REJECT)) { |
243 | /* | 251 | /* |
244 | * if the device doesn't support the SenseID | 252 | * if the device doesn't support the SenseID |
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 2975ce888c19..cb1879a96818 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -71,6 +71,8 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) | |||
71 | ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); | 71 | ccw->cda = (__u32) __pa (&cdev->private->pgid[i]); |
72 | if (cdev->private->iretry > 0) { | 72 | if (cdev->private->iretry > 0) { |
73 | cdev->private->iretry--; | 73 | cdev->private->iretry--; |
74 | /* Reset internal retry indication. */ | ||
75 | cdev->private->flags.intretry = 0; | ||
74 | ret = cio_start (sch, cdev->private->iccws, | 76 | ret = cio_start (sch, cdev->private->iccws, |
75 | cdev->private->imask); | 77 | cdev->private->imask); |
76 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ | 78 | /* ret is 0, -EBUSY, -EACCES or -ENODEV */ |
@@ -122,8 +124,14 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) | |||
122 | 124 | ||
123 | sch = to_subchannel(cdev->dev.parent); | 125 | sch = to_subchannel(cdev->dev.parent); |
124 | irb = &cdev->private->irb; | 126 | irb = &cdev->private->irb; |
125 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 127 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
128 | /* Retry Sense PGID if requested. */ | ||
129 | if (cdev->private->flags.intretry) { | ||
130 | cdev->private->flags.intretry = 0; | ||
131 | return -EAGAIN; | ||
132 | } | ||
126 | return -ETIME; | 133 | return -ETIME; |
134 | } | ||
127 | if (irb->esw.esw0.erw.cons && | 135 | if (irb->esw.esw0.erw.cons && |
128 | (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { | 136 | (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) { |
129 | /* | 137 | /* |
@@ -253,6 +261,8 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) | |||
253 | ret = -EACCES; | 261 | ret = -EACCES; |
254 | if (cdev->private->iretry > 0) { | 262 | if (cdev->private->iretry > 0) { |
255 | cdev->private->iretry--; | 263 | cdev->private->iretry--; |
264 | /* Reset internal retry indication. */ | ||
265 | cdev->private->flags.intretry = 0; | ||
256 | ret = cio_start (sch, cdev->private->iccws, | 266 | ret = cio_start (sch, cdev->private->iccws, |
257 | cdev->private->imask); | 267 | cdev->private->imask); |
258 | /* We expect an interrupt in case of success or busy | 268 | /* We expect an interrupt in case of success or busy |
@@ -293,6 +303,8 @@ static int __ccw_device_do_nop(struct ccw_device *cdev) | |||
293 | ret = -EACCES; | 303 | ret = -EACCES; |
294 | if (cdev->private->iretry > 0) { | 304 | if (cdev->private->iretry > 0) { |
295 | cdev->private->iretry--; | 305 | cdev->private->iretry--; |
306 | /* Reset internal retry indication. */ | ||
307 | cdev->private->flags.intretry = 0; | ||
296 | ret = cio_start (sch, cdev->private->iccws, | 308 | ret = cio_start (sch, cdev->private->iccws, |
297 | cdev->private->imask); | 309 | cdev->private->imask); |
298 | /* We expect an interrupt in case of success or busy | 310 | /* We expect an interrupt in case of success or busy |
@@ -321,8 +333,14 @@ __ccw_device_check_pgid(struct ccw_device *cdev) | |||
321 | 333 | ||
322 | sch = to_subchannel(cdev->dev.parent); | 334 | sch = to_subchannel(cdev->dev.parent); |
323 | irb = &cdev->private->irb; | 335 | irb = &cdev->private->irb; |
324 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 336 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
337 | /* Retry Set PGID if requested. */ | ||
338 | if (cdev->private->flags.intretry) { | ||
339 | cdev->private->flags.intretry = 0; | ||
340 | return -EAGAIN; | ||
341 | } | ||
325 | return -ETIME; | 342 | return -ETIME; |
343 | } | ||
326 | if (irb->esw.esw0.erw.cons) { | 344 | if (irb->esw.esw0.erw.cons) { |
327 | if (irb->ecw[0] & SNS0_CMD_REJECT) | 345 | if (irb->ecw[0] & SNS0_CMD_REJECT) |
328 | return -EOPNOTSUPP; | 346 | return -EOPNOTSUPP; |
@@ -360,8 +378,14 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) | |||
360 | 378 | ||
361 | sch = to_subchannel(cdev->dev.parent); | 379 | sch = to_subchannel(cdev->dev.parent); |
362 | irb = &cdev->private->irb; | 380 | irb = &cdev->private->irb; |
363 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) | 381 | if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { |
382 | /* Retry NOP if requested. */ | ||
383 | if (cdev->private->flags.intretry) { | ||
384 | cdev->private->flags.intretry = 0; | ||
385 | return -EAGAIN; | ||
386 | } | ||
364 | return -ETIME; | 387 | return -ETIME; |
388 | } | ||
365 | if (irb->scsw.cc == 3) { | 389 | if (irb->scsw.cc == 3) { |
366 | CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," | 390 | CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x," |
367 | " lpm %02X, became 'not operational'\n", | 391 | " lpm %02X, became 'not operational'\n", |
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 3f7cbce4cd87..bdcf930f7beb 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c | |||
@@ -319,6 +319,9 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) | |||
319 | sch->sense_ccw.count = SENSE_MAX_COUNT; | 319 | sch->sense_ccw.count = SENSE_MAX_COUNT; |
320 | sch->sense_ccw.flags = CCW_FLAG_SLI; | 320 | sch->sense_ccw.flags = CCW_FLAG_SLI; |
321 | 321 | ||
322 | /* Reset internal retry indication. */ | ||
323 | cdev->private->flags.intretry = 0; | ||
324 | |||
322 | return cio_start (sch, &sch->sense_ccw, 0xff); | 325 | return cio_start (sch, &sch->sense_ccw, 0xff); |
323 | } | 326 | } |
324 | 327 | ||
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 476aa1da5cbc..8d5fa1b4d11f 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -481,7 +481,7 @@ qdio_stop_polling(struct qdio_q *q) | |||
481 | unsigned char state = 0; | 481 | unsigned char state = 0; |
482 | struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr; | 482 | struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr; |
483 | 483 | ||
484 | if (!atomic_swap(&q->polling,0)) | 484 | if (!atomic_xchg(&q->polling,0)) |
485 | return 1; | 485 | return 1; |
486 | 486 | ||
487 | QDIO_DBF_TEXT4(0,trace,"stoppoll"); | 487 | QDIO_DBF_TEXT4(0,trace,"stoppoll"); |
@@ -1964,8 +1964,8 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) | |||
1964 | QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN); | 1964 | QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN); |
1965 | 1965 | ||
1966 | QDIO_PRINT_WARN("sense data available on qdio channel.\n"); | 1966 | QDIO_PRINT_WARN("sense data available on qdio channel.\n"); |
1967 | HEXDUMP16(WARN,"irb: ",irb); | 1967 | QDIO_HEXDUMP16(WARN,"irb: ",irb); |
1968 | HEXDUMP16(WARN,"sense data: ",irb->ecw); | 1968 | QDIO_HEXDUMP16(WARN,"sense data: ",irb->ecw); |
1969 | } | 1969 | } |
1970 | 1970 | ||
1971 | } | 1971 | } |
@@ -3425,7 +3425,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, | |||
3425 | 3425 | ||
3426 | if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&& | 3426 | if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&& |
3427 | (callflags&QDIO_FLAG_UNDER_INTERRUPT)) | 3427 | (callflags&QDIO_FLAG_UNDER_INTERRUPT)) |
3428 | atomic_swap(&q->polling,0); | 3428 | atomic_xchg(&q->polling,0); |
3429 | 3429 | ||
3430 | if (used_elements) | 3430 | if (used_elements) |
3431 | return; | 3431 | return; |
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 49bb9e371c32..42927c1b7451 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -236,7 +236,7 @@ enum qdio_irq_states { | |||
236 | #define QDIO_PRINT_EMERG(x...) do { } while (0) | 236 | #define QDIO_PRINT_EMERG(x...) do { } while (0) |
237 | #endif | 237 | #endif |
238 | 238 | ||
239 | #define HEXDUMP16(importance,header,ptr) \ | 239 | #define QDIO_HEXDUMP16(importance,header,ptr) \ |
240 | QDIO_PRINT_##importance(header "%02x %02x %02x %02x " \ | 240 | QDIO_PRINT_##importance(header "%02x %02x %02x %02x " \ |
241 | "%02x %02x %02x %02x %02x %02x %02x %02x " \ | 241 | "%02x %02x %02x %02x %02x %02x %02x %02x " \ |
242 | "%02x %02x %02x %02x\n",*(((char*)ptr)), \ | 242 | "%02x %02x %02x %02x\n",*(((char*)ptr)), \ |
@@ -429,8 +429,6 @@ struct qdio_perf_stats { | |||
429 | }; | 429 | }; |
430 | #endif /* QDIO_PERFORMANCE_STATS */ | 430 | #endif /* QDIO_PERFORMANCE_STATS */ |
431 | 431 | ||
432 | #define atomic_swap(a,b) xchg((int*)a.counter,b) | ||
433 | |||
434 | /* unlikely as the later the better */ | 432 | /* unlikely as the later the better */ |
435 | #define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q) | 433 | #define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q) |
436 | #define SYNC_MEMORY_ALL if (unlikely(q->siga_sync)) \ | 434 | #define SYNC_MEMORY_ALL if (unlikely(q->siga_sync)) \ |