diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_attr.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e058f1018ff2..82005b8ad957 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/aer.h> | ||
26 | 27 | ||
27 | #include <scsi/scsi.h> | 28 | #include <scsi/scsi.h> |
28 | #include <scsi/scsi_device.h> | 29 | #include <scsi/scsi_device.h> |
@@ -2766,6 +2767,179 @@ static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR, | |||
2766 | lpfc_link_speed_show, lpfc_link_speed_store); | 2767 | lpfc_link_speed_show, lpfc_link_speed_store); |
2767 | 2768 | ||
2768 | /* | 2769 | /* |
2770 | # lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER) | ||
2771 | # 0 = aer disabled or not supported | ||
2772 | # 1 = aer supported and enabled (default) | ||
2773 | # Value range is [0,1]. Default value is 1. | ||
2774 | */ | ||
2775 | |||
2776 | /** | ||
2777 | * lpfc_aer_support_store - Set the adapter for aer support | ||
2778 | * | ||
2779 | * @dev: class device that is converted into a Scsi_host. | ||
2780 | * @attr: device attribute, not used. | ||
2781 | * @buf: containing the string "selective". | ||
2782 | * @count: unused variable. | ||
2783 | * | ||
2784 | * Description: | ||
2785 | * If the val is 1 and currently the device's AER capability was not | ||
2786 | * enabled, invoke the kernel's enable AER helper routine, trying to | ||
2787 | * enable the device's AER capability. If the helper routine enabling | ||
2788 | * AER returns success, update the device's cfg_aer_support flag to | ||
2789 | * indicate AER is supported by the device; otherwise, if the device | ||
2790 | * AER capability is already enabled to support AER, then do nothing. | ||
2791 | * | ||
2792 | * If the val is 0 and currently the device's AER support was enabled, | ||
2793 | * invoke the kernel's disable AER helper routine. After that, update | ||
2794 | * the device's cfg_aer_support flag to indicate AER is not supported | ||
2795 | * by the device; otherwise, if the device AER capability is already | ||
2796 | * disabled from supporting AER, then do nothing. | ||
2797 | * | ||
2798 | * Returns: | ||
2799 | * length of the buf on success if val is in range the intended mode | ||
2800 | * is supported. | ||
2801 | * -EINVAL if val out of range or intended mode is not supported. | ||
2802 | **/ | ||
2803 | static ssize_t | ||
2804 | lpfc_aer_support_store(struct device *dev, struct device_attribute *attr, | ||
2805 | const char *buf, size_t count) | ||
2806 | { | ||
2807 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2808 | struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; | ||
2809 | struct lpfc_hba *phba = vport->phba; | ||
2810 | int val = 0, rc = -EINVAL; | ||
2811 | |||
2812 | if (!isdigit(buf[0])) | ||
2813 | return -EINVAL; | ||
2814 | if (sscanf(buf, "%i", &val) != 1) | ||
2815 | return -EINVAL; | ||
2816 | |||
2817 | switch (val) { | ||
2818 | case 0: | ||
2819 | if (phba->hba_flag & HBA_AER_ENABLED) { | ||
2820 | rc = pci_disable_pcie_error_reporting(phba->pcidev); | ||
2821 | if (!rc) { | ||
2822 | spin_lock_irq(&phba->hbalock); | ||
2823 | phba->hba_flag &= ~HBA_AER_ENABLED; | ||
2824 | spin_unlock_irq(&phba->hbalock); | ||
2825 | phba->cfg_aer_support = 0; | ||
2826 | rc = strlen(buf); | ||
2827 | } else | ||
2828 | rc = -EINVAL; | ||
2829 | } else | ||
2830 | phba->cfg_aer_support = 0; | ||
2831 | rc = strlen(buf); | ||
2832 | break; | ||
2833 | case 1: | ||
2834 | if (!(phba->hba_flag & HBA_AER_ENABLED)) { | ||
2835 | rc = pci_enable_pcie_error_reporting(phba->pcidev); | ||
2836 | if (!rc) { | ||
2837 | spin_lock_irq(&phba->hbalock); | ||
2838 | phba->hba_flag |= HBA_AER_ENABLED; | ||
2839 | spin_unlock_irq(&phba->hbalock); | ||
2840 | phba->cfg_aer_support = 1; | ||
2841 | rc = strlen(buf); | ||
2842 | } else | ||
2843 | rc = -EINVAL; | ||
2844 | } else | ||
2845 | phba->cfg_aer_support = 1; | ||
2846 | rc = strlen(buf); | ||
2847 | break; | ||
2848 | default: | ||
2849 | rc = -EINVAL; | ||
2850 | break; | ||
2851 | } | ||
2852 | return rc; | ||
2853 | } | ||
2854 | |||
2855 | static int lpfc_aer_support = 1; | ||
2856 | module_param(lpfc_aer_support, int, 1); | ||
2857 | MODULE_PARM_DESC(lpfc_aer_support, "Enable PCIe device AER support"); | ||
2858 | lpfc_param_show(aer_support) | ||
2859 | |||
2860 | /** | ||
2861 | * lpfc_aer_support_init - Set the initial adapters aer support flag | ||
2862 | * @phba: lpfc_hba pointer. | ||
2863 | * @val: link speed value. | ||
2864 | * | ||
2865 | * Description: | ||
2866 | * If val is in a valid range [0,1], then set the adapter's initial | ||
2867 | * cfg_aer_support field. It will be up to the driver's probe_one | ||
2868 | * routine to determine whether the device's AER support can be set | ||
2869 | * or not. | ||
2870 | * | ||
2871 | * Notes: | ||
2872 | * If the value is not in range log a kernel error message, and | ||
2873 | * choose the default value of setting AER support and return. | ||
2874 | * | ||
2875 | * Returns: | ||
2876 | * zero if val saved. | ||
2877 | * -EINVAL val out of range | ||
2878 | **/ | ||
2879 | static int | ||
2880 | lpfc_aer_support_init(struct lpfc_hba *phba, int val) | ||
2881 | { | ||
2882 | if (val == 0 || val == 1) { | ||
2883 | phba->cfg_aer_support = val; | ||
2884 | return 0; | ||
2885 | } | ||
2886 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
2887 | "2712 lpfc_aer_support attribute value %d out " | ||
2888 | "of range, allowed values are 0|1, setting it " | ||
2889 | "to default value of 1\n", val); | ||
2890 | phba->cfg_aer_support = 1; | ||
2891 | return -EINVAL; | ||
2892 | } | ||
2893 | |||
2894 | static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR, | ||
2895 | lpfc_aer_support_show, lpfc_aer_support_store); | ||
2896 | |||
2897 | /** | ||
2898 | * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device | ||
2899 | * @dev: class device that is converted into a Scsi_host. | ||
2900 | * @attr: device attribute, not used. | ||
2901 | * @buf: containing the string "selective". | ||
2902 | * @count: unused variable. | ||
2903 | * | ||
2904 | * Description: | ||
2905 | * If the @buf contains 1 and the device currently has the AER support | ||
2906 | * enabled, then invokes the kernel AER helper routine | ||
2907 | * pci_cleanup_aer_uncorrect_error_status to clean up the uncorrectable | ||
2908 | * error status register. | ||
2909 | * | ||
2910 | * Notes: | ||
2911 | * | ||
2912 | * Returns: | ||
2913 | * -EINVAL if the buf does not contain the 1 or the device is not currently | ||
2914 | * enabled with the AER support. | ||
2915 | **/ | ||
2916 | static ssize_t | ||
2917 | lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr, | ||
2918 | const char *buf, size_t count) | ||
2919 | { | ||
2920 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2921 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | ||
2922 | struct lpfc_hba *phba = vport->phba; | ||
2923 | int val, rc = -1; | ||
2924 | |||
2925 | if (!isdigit(buf[0])) | ||
2926 | return -EINVAL; | ||
2927 | if (sscanf(buf, "%i", &val) != 1) | ||
2928 | return -EINVAL; | ||
2929 | |||
2930 | if (val == 1 && phba->hba_flag & HBA_AER_ENABLED) | ||
2931 | rc = pci_cleanup_aer_uncorrect_error_status(phba->pcidev); | ||
2932 | |||
2933 | if (rc == 0) | ||
2934 | return strlen(buf); | ||
2935 | else | ||
2936 | return -EINVAL; | ||
2937 | } | ||
2938 | |||
2939 | static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL, | ||
2940 | lpfc_aer_cleanup_state); | ||
2941 | |||
2942 | /* | ||
2769 | # lpfc_fcp_class: Determines FC class to use for the FCP protocol. | 2943 | # lpfc_fcp_class: Determines FC class to use for the FCP protocol. |
2770 | # Value range is [2,3]. Default value is 3. | 2944 | # Value range is [2,3]. Default value is 3. |
2771 | */ | 2945 | */ |
@@ -3068,6 +3242,8 @@ struct device_attribute *lpfc_hba_attrs[] = { | |||
3068 | &dev_attr_lpfc_max_scsicmpl_time, | 3242 | &dev_attr_lpfc_max_scsicmpl_time, |
3069 | &dev_attr_lpfc_stat_data_ctrl, | 3243 | &dev_attr_lpfc_stat_data_ctrl, |
3070 | &dev_attr_lpfc_prot_sg_seg_cnt, | 3244 | &dev_attr_lpfc_prot_sg_seg_cnt, |
3245 | &dev_attr_lpfc_aer_support, | ||
3246 | &dev_attr_lpfc_aer_state_cleanup, | ||
3071 | NULL, | 3247 | NULL, |
3072 | }; | 3248 | }; |
3073 | 3249 | ||
@@ -4244,6 +4420,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) | |||
4244 | lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); | 4420 | lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); |
4245 | lpfc_enable_fip_init(phba, lpfc_enable_fip); | 4421 | lpfc_enable_fip_init(phba, lpfc_enable_fip); |
4246 | lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); | 4422 | lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); |
4423 | lpfc_aer_support_init(phba, lpfc_aer_support); | ||
4247 | 4424 | ||
4248 | return; | 4425 | return; |
4249 | } | 4426 | } |