aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2009-10-02 15:16:56 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:01:41 -0500
commit0d87841997125971b7a39d21d1435054f91884c3 (patch)
treea30a4fe442ddc654ef170b40e7e2e66199bbad18
parent6a9c52cf22e4ca13816bb2bd9899129cd4445de7 (diff)
[SCSI] lpfc 8.3.5: Add AER support
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/lpfc/lpfc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c177
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c96
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c27
4 files changed, 278 insertions, 24 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index c618eaf3c0c8..e5ebb5343421 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -534,6 +534,7 @@ struct lpfc_hba {
534#define ASYNC_EVENT 0x80 534#define ASYNC_EVENT 0x80
535#define LINK_DISABLED 0x100 /* Link disabled by user */ 535#define LINK_DISABLED 0x100 /* Link disabled by user */
536#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */ 536#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */
537#define HBA_AER_ENABLED 0x800 /* AER enabled with HBA */
537 struct lpfc_dmabuf slim2p; 538 struct lpfc_dmabuf slim2p;
538 539
539 MAILBOX_t *mbox; 540 MAILBOX_t *mbox;
@@ -607,6 +608,7 @@ struct lpfc_hba {
607 uint32_t cfg_enable_bg; 608 uint32_t cfg_enable_bg;
608 uint32_t cfg_enable_fip; 609 uint32_t cfg_enable_fip;
609 uint32_t cfg_log_verbose; 610 uint32_t cfg_log_verbose;
611 uint32_t cfg_aer_support;
610 612
611 lpfc_vpd_t vpd; /* vital product data */ 613 lpfc_vpd_t vpd; /* vital product data */
612 614
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 **/
2803static ssize_t
2804lpfc_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
2855static int lpfc_aer_support = 1;
2856module_param(lpfc_aer_support, int, 1);
2857MODULE_PARM_DESC(lpfc_aer_support, "Enable PCIe device AER support");
2858lpfc_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 **/
2879static int
2880lpfc_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
2894static 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 **/
2916static ssize_t
2917lpfc_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
2939static 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}
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 12ab1eae47f9..61925836a09e 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -28,6 +28,7 @@
28#include <linux/pci.h> 28#include <linux/pci.h>
29#include <linux/spinlock.h> 29#include <linux/spinlock.h>
30#include <linux/ctype.h> 30#include <linux/ctype.h>
31#include <linux/aer.h>
31 32
32#include <scsi/scsi.h> 33#include <scsi/scsi.h>
33#include <scsi/scsi_device.h> 34#include <scsi/scsi_device.h>
@@ -7098,6 +7099,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
7098 /* Restore device state from PCI config space */ 7099 /* Restore device state from PCI config space */
7099 pci_set_power_state(pdev, PCI_D0); 7100 pci_set_power_state(pdev, PCI_D0);
7100 pci_restore_state(pdev); 7101 pci_restore_state(pdev);
7102
7101 if (pdev->is_busmaster) 7103 if (pdev->is_busmaster)
7102 pci_set_master(pdev); 7104 pci_set_master(pdev);
7103 7105
@@ -7132,6 +7134,53 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
7132} 7134}
7133 7135
7134/** 7136/**
7137 * lpfc_sli_prep_dev_for_reset - Prepare SLI3 device for pci slot reset
7138 * @phba: pointer to lpfc hba data structure.
7139 *
7140 * This routine is called to prepare the SLI3 device for PCI slot reset. It
7141 * disables the device interrupt and pci device, and aborts the internal FCP
7142 * pending I/Os.
7143 **/
7144static void
7145lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
7146{
7147 struct lpfc_sli *psli = &phba->sli;
7148 struct lpfc_sli_ring *pring;
7149
7150 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
7151 "2710 PCI channel I/O frozen\n");
7152 /* Disable interrupt and pci device */
7153 lpfc_sli_disable_intr(phba);
7154 pci_disable_device(phba->pcidev);
7155 /*
7156 * There may be I/Os dropped by the firmware.
7157 * Error iocb (I/O) on txcmplq and let the SCSI layer
7158 * retry it after re-establishing link.
7159 */
7160 pring = &psli->ring[psli->fcp_ring];
7161 lpfc_sli_abort_iocb_ring(phba, pring);
7162}
7163
7164/**
7165 * lpfc_sli_prep_dev_for_perm_failure - Prepare SLI3 dev for pci slot disable
7166 * @phba: pointer to lpfc hba data structure.
7167 *
7168 * This routine is called to prepare the SLI3 device for PCI slot permanently
7169 * disabling. It blocks the SCSI transport layer traffic and flushes the FCP
7170 * pending I/Os.
7171 **/
7172static void
7173lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
7174{
7175 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
7176 "2711 PCI channel I/O permanent failure\n");
7177 /* Block all SCSI devices' I/Os on the host */
7178 lpfc_scsi_dev_block(phba);
7179 /* Clean up all driver's outstanding SCSI I/Os */
7180 lpfc_sli_flush_fcp_rings(phba);
7181}
7182
7183/**
7135 * lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error 7184 * lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error
7136 * @pdev: pointer to PCI device. 7185 * @pdev: pointer to PCI device.
7137 * @state: the current PCI connection state. 7186 * @state: the current PCI connection state.
@@ -7145,6 +7194,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
7145 * as desired. 7194 * as desired.
7146 * 7195 *
7147 * Return codes 7196 * Return codes
7197 * PCI_ERS_RESULT_CAN_RECOVER - can be recovered with reset_link
7148 * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery 7198 * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery
7149 * PCI_ERS_RESULT_DISCONNECT - device could not be recovered 7199 * PCI_ERS_RESULT_DISCONNECT - device could not be recovered
7150 **/ 7200 **/
@@ -7153,33 +7203,26 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
7153{ 7203{
7154 struct Scsi_Host *shost = pci_get_drvdata(pdev); 7204 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7155 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; 7205 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
7156 struct lpfc_sli *psli = &phba->sli;
7157 struct lpfc_sli_ring *pring;
7158 7206
7159 if (state == pci_channel_io_perm_failure) { 7207 switch (state) {
7160 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 7208 case pci_channel_io_normal:
7161 "0472 PCI channel I/O permanent failure\n"); 7209 /* Non-fatal error, do nothing */
7162 /* Block all SCSI devices' I/Os on the host */ 7210 return PCI_ERS_RESULT_CAN_RECOVER;
7163 lpfc_scsi_dev_block(phba); 7211 case pci_channel_io_frozen:
7164 /* Clean up all driver's outstanding SCSI I/Os */ 7212 /* Fatal error, prepare for slot reset */
7165 lpfc_sli_flush_fcp_rings(phba); 7213 lpfc_sli_prep_dev_for_reset(phba);
7214 return PCI_ERS_RESULT_NEED_RESET;
7215 case pci_channel_io_perm_failure:
7216 /* Permanent failure, prepare for device down */
7217 lpfc_prep_dev_for_perm_failure(phba);
7166 return PCI_ERS_RESULT_DISCONNECT; 7218 return PCI_ERS_RESULT_DISCONNECT;
7219 default:
7220 /* Unknown state, prepare and request slot reset */
7221 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
7222 "0472 Unknown PCI error state: x%x\n", state);
7223 lpfc_sli_prep_dev_for_reset(phba);
7224 return PCI_ERS_RESULT_NEED_RESET;
7167 } 7225 }
7168
7169 pci_disable_device(pdev);
7170 /*
7171 * There may be I/Os dropped by the firmware.
7172 * Error iocb (I/O) on txcmplq and let the SCSI layer
7173 * retry it after re-establishing link.
7174 */
7175 pring = &psli->ring[psli->fcp_ring];
7176 lpfc_sli_abort_iocb_ring(phba, pring);
7177
7178 /* Disable interrupt */
7179 lpfc_sli_disable_intr(phba);
7180
7181 /* Request a slot reset. */
7182 return PCI_ERS_RESULT_NEED_RESET;
7183} 7226}
7184 7227
7185/** 7228/**
@@ -7259,7 +7302,12 @@ lpfc_io_resume_s3(struct pci_dev *pdev)
7259 struct Scsi_Host *shost = pci_get_drvdata(pdev); 7302 struct Scsi_Host *shost = pci_get_drvdata(pdev);
7260 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; 7303 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
7261 7304
7305 /* Bring the device online */
7262 lpfc_online(phba); 7306 lpfc_online(phba);
7307
7308 /* Clean up Advanced Error Reporting (AER) if needed */
7309 if (phba->hba_flag & HBA_AER_ENABLED)
7310 pci_cleanup_aer_uncorrect_error_status(pdev);
7263} 7311}
7264 7312
7265/** 7313/**
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 9693c777425a..42d0f1948a7a 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -30,6 +30,7 @@
30#include <scsi/scsi_host.h> 30#include <scsi/scsi_host.h>
31#include <scsi/scsi_transport_fc.h> 31#include <scsi/scsi_transport_fc.h>
32#include <scsi/fc/fc_fs.h> 32#include <scsi/fc/fc_fs.h>
33#include <linux/aer.h>
33 34
34#include "lpfc_hw4.h" 35#include "lpfc_hw4.h"
35#include "lpfc_hw.h" 36#include "lpfc_hw.h"
@@ -3551,9 +3552,13 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba)
3551 struct lpfc_sli *psli; 3552 struct lpfc_sli *psli;
3552 volatile uint32_t word0; 3553 volatile uint32_t word0;
3553 void __iomem *to_slim; 3554 void __iomem *to_slim;
3555 uint32_t hba_aer_enabled;
3554 3556
3555 spin_lock_irq(&phba->hbalock); 3557 spin_lock_irq(&phba->hbalock);
3556 3558
3559 /* Take PCIe device Advanced Error Reporting (AER) state */
3560 hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
3561
3557 psli = &phba->sli; 3562 psli = &phba->sli;
3558 3563
3559 /* Restart HBA */ 3564 /* Restart HBA */
@@ -3593,6 +3598,10 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba)
3593 /* Give the INITFF and Post time to settle. */ 3598 /* Give the INITFF and Post time to settle. */
3594 mdelay(100); 3599 mdelay(100);
3595 3600
3601 /* Reset HBA AER if it was enabled, note hba_flag was reset above */
3602 if (hba_aer_enabled)
3603 pci_disable_pcie_error_reporting(phba->pcidev);
3604
3596 lpfc_hba_down_post(phba); 3605 lpfc_hba_down_post(phba);
3597 3606
3598 return 0; 3607 return 0;
@@ -4062,6 +4071,24 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
4062 if (rc) 4071 if (rc)
4063 goto lpfc_sli_hba_setup_error; 4072 goto lpfc_sli_hba_setup_error;
4064 4073
4074 /* Enable PCIe device Advanced Error Reporting (AER) if configured */
4075 if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {
4076 rc = pci_enable_pcie_error_reporting(phba->pcidev);
4077 if (!rc) {
4078 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
4079 "2709 This device supports "
4080 "Advanced Error Reporting (AER)\n");
4081 spin_lock_irq(&phba->hbalock);
4082 phba->hba_flag |= HBA_AER_ENABLED;
4083 spin_unlock_irq(&phba->hbalock);
4084 } else {
4085 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
4086 "2708 This device does not support "
4087 "Advanced Error Reporting (AER)\n");
4088 phba->cfg_aer_support = 0;
4089 }
4090 }
4091
4065 if (phba->sli_rev == 3) { 4092 if (phba->sli_rev == 3) {
4066 phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE; 4093 phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
4067 phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE; 4094 phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;