diff options
author | James Smart <james.smart@emulex.com> | 2010-06-08 18:31:21 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 13:01:35 -0400 |
commit | 75baf69657ea2107f2c202cd29dada206ae4b7c4 (patch) | |
tree | 76f48393730c19e0a0286ceaa5132d8e500f127f /drivers/scsi/lpfc | |
parent | c20c426732a5a5d21e99b36286f79c2024115341 (diff) |
[SCSI] lpfc 8.3.14: PCI fixes and enhancements
- Allow enabling MSI-X intterupts with fewer vectors than requested
by looking at the return value from pci_enable_msix.
- Implemented driver PCI AER error handling routines for supporting
AER error recovering on SLI4 devices.
- Remove redundant SLI_ACTIVE checks
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 22 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 195 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 10 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 41 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 1 |
5 files changed, 228 insertions, 41 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 39b0760c438d..a7c6b7390554 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -864,7 +864,6 @@ lpfc_get_hba_info(struct lpfc_hba *phba, | |||
864 | uint32_t *mrpi, uint32_t *arpi, | 864 | uint32_t *mrpi, uint32_t *arpi, |
865 | uint32_t *mvpi, uint32_t *avpi) | 865 | uint32_t *mvpi, uint32_t *avpi) |
866 | { | 866 | { |
867 | struct lpfc_sli *psli = &phba->sli; | ||
868 | struct lpfc_mbx_read_config *rd_config; | 867 | struct lpfc_mbx_read_config *rd_config; |
869 | LPFC_MBOXQ_t *pmboxq; | 868 | LPFC_MBOXQ_t *pmboxq; |
870 | MAILBOX_t *pmb; | 869 | MAILBOX_t *pmb; |
@@ -893,8 +892,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, | |||
893 | pmb->mbxOwner = OWN_HOST; | 892 | pmb->mbxOwner = OWN_HOST; |
894 | pmboxq->context1 = NULL; | 893 | pmboxq->context1 = NULL; |
895 | 894 | ||
896 | if ((phba->pport->fc_flag & FC_OFFLINE_MODE) || | 895 | if (phba->pport->fc_flag & FC_OFFLINE_MODE) |
897 | (!(psli->sli_flag & LPFC_SLI_ACTIVE))) | ||
898 | rc = MBX_NOT_FINISHED; | 896 | rc = MBX_NOT_FINISHED; |
899 | else | 897 | else |
900 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); | 898 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); |
@@ -2943,9 +2941,6 @@ lpfc_aer_support_store(struct device *dev, struct device_attribute *attr, | |||
2943 | struct lpfc_hba *phba = vport->phba; | 2941 | struct lpfc_hba *phba = vport->phba; |
2944 | int val = 0, rc = -EINVAL; | 2942 | int val = 0, rc = -EINVAL; |
2945 | 2943 | ||
2946 | /* AER not supported on OC devices yet */ | ||
2947 | if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) | ||
2948 | return -EPERM; | ||
2949 | if (!isdigit(buf[0])) | 2944 | if (!isdigit(buf[0])) |
2950 | return -EINVAL; | 2945 | return -EINVAL; |
2951 | if (sscanf(buf, "%i", &val) != 1) | 2946 | if (sscanf(buf, "%i", &val) != 1) |
@@ -3018,12 +3013,6 @@ lpfc_param_show(aer_support) | |||
3018 | static int | 3013 | static int |
3019 | lpfc_aer_support_init(struct lpfc_hba *phba, int val) | 3014 | lpfc_aer_support_init(struct lpfc_hba *phba, int val) |
3020 | { | 3015 | { |
3021 | /* AER not supported on OC devices yet */ | ||
3022 | if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { | ||
3023 | phba->cfg_aer_support = 0; | ||
3024 | return -EPERM; | ||
3025 | } | ||
3026 | |||
3027 | if (val == 0 || val == 1) { | 3016 | if (val == 0 || val == 1) { |
3028 | phba->cfg_aer_support = val; | 3017 | phba->cfg_aer_support = val; |
3029 | return 0; | 3018 | return 0; |
@@ -3068,9 +3057,6 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr, | |||
3068 | struct lpfc_hba *phba = vport->phba; | 3057 | struct lpfc_hba *phba = vport->phba; |
3069 | int val, rc = -1; | 3058 | int val, rc = -1; |
3070 | 3059 | ||
3071 | /* AER not supported on OC devices yet */ | ||
3072 | if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) | ||
3073 | return -EPERM; | ||
3074 | if (!isdigit(buf[0])) | 3060 | if (!isdigit(buf[0])) |
3075 | return -EINVAL; | 3061 | return -EINVAL; |
3076 | if (sscanf(buf, "%i", &val) != 1) | 3062 | if (sscanf(buf, "%i", &val) != 1) |
@@ -4099,8 +4085,7 @@ lpfc_get_stats(struct Scsi_Host *shost) | |||
4099 | pmboxq->context1 = NULL; | 4085 | pmboxq->context1 = NULL; |
4100 | pmboxq->vport = vport; | 4086 | pmboxq->vport = vport; |
4101 | 4087 | ||
4102 | if ((vport->fc_flag & FC_OFFLINE_MODE) || | 4088 | if (vport->fc_flag & FC_OFFLINE_MODE) |
4103 | (!(psli->sli_flag & LPFC_SLI_ACTIVE))) | ||
4104 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); | 4089 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); |
4105 | else | 4090 | else |
4106 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); | 4091 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); |
@@ -4124,8 +4109,7 @@ lpfc_get_stats(struct Scsi_Host *shost) | |||
4124 | pmboxq->context1 = NULL; | 4109 | pmboxq->context1 = NULL; |
4125 | pmboxq->vport = vport; | 4110 | pmboxq->vport = vport; |
4126 | 4111 | ||
4127 | if ((vport->fc_flag & FC_OFFLINE_MODE) || | 4112 | if (vport->fc_flag & FC_OFFLINE_MODE) |
4128 | (!(psli->sli_flag & LPFC_SLI_ACTIVE))) | ||
4129 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); | 4113 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); |
4130 | else | 4114 | else |
4131 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); | 4115 | rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 184e45f286d2..08db674ec580 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -7030,22 +7030,28 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba) | |||
7030 | static int | 7030 | static int |
7031 | lpfc_sli4_enable_msix(struct lpfc_hba *phba) | 7031 | lpfc_sli4_enable_msix(struct lpfc_hba *phba) |
7032 | { | 7032 | { |
7033 | int rc, index; | 7033 | int vectors, rc, index; |
7034 | 7034 | ||
7035 | /* Set up MSI-X multi-message vectors */ | 7035 | /* Set up MSI-X multi-message vectors */ |
7036 | for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) | 7036 | for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) |
7037 | phba->sli4_hba.msix_entries[index].entry = index; | 7037 | phba->sli4_hba.msix_entries[index].entry = index; |
7038 | 7038 | ||
7039 | /* Configure MSI-X capability structure */ | 7039 | /* Configure MSI-X capability structure */ |
7040 | vectors = phba->sli4_hba.cfg_eqn; | ||
7041 | enable_msix_vectors: | ||
7040 | rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries, | 7042 | rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries, |
7041 | phba->sli4_hba.cfg_eqn); | 7043 | vectors); |
7042 | if (rc) { | 7044 | if (rc > 1) { |
7045 | vectors = rc; | ||
7046 | goto enable_msix_vectors; | ||
7047 | } else if (rc) { | ||
7043 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 7048 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
7044 | "0484 PCI enable MSI-X failed (%d)\n", rc); | 7049 | "0484 PCI enable MSI-X failed (%d)\n", rc); |
7045 | goto msi_fail_out; | 7050 | goto msi_fail_out; |
7046 | } | 7051 | } |
7052 | |||
7047 | /* Log MSI-X vector assignment */ | 7053 | /* Log MSI-X vector assignment */ |
7048 | for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) | 7054 | for (index = 0; index < vectors; index++) |
7049 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 7055 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
7050 | "0489 MSI-X entry[%d]: vector=x%x " | 7056 | "0489 MSI-X entry[%d]: vector=x%x " |
7051 | "message=%d\n", index, | 7057 | "message=%d\n", index, |
@@ -7067,7 +7073,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) | |||
7067 | } | 7073 | } |
7068 | 7074 | ||
7069 | /* The rest of the vector(s) are associated to fast-path handler(s) */ | 7075 | /* The rest of the vector(s) are associated to fast-path handler(s) */ |
7070 | for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) { | 7076 | for (index = 1; index < vectors; index++) { |
7071 | phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1; | 7077 | phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1; |
7072 | phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba; | 7078 | phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba; |
7073 | rc = request_irq(phba->sli4_hba.msix_entries[index].vector, | 7079 | rc = request_irq(phba->sli4_hba.msix_entries[index].vector, |
@@ -7081,6 +7087,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) | |||
7081 | goto cfg_fail_out; | 7087 | goto cfg_fail_out; |
7082 | } | 7088 | } |
7083 | } | 7089 | } |
7090 | phba->sli4_hba.msix_vec_nr = vectors; | ||
7084 | 7091 | ||
7085 | return rc; | 7092 | return rc; |
7086 | 7093 | ||
@@ -7114,9 +7121,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba) | |||
7114 | /* Free up MSI-X multi-message vectors */ | 7121 | /* Free up MSI-X multi-message vectors */ |
7115 | free_irq(phba->sli4_hba.msix_entries[0].vector, phba); | 7122 | free_irq(phba->sli4_hba.msix_entries[0].vector, phba); |
7116 | 7123 | ||
7117 | for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) | 7124 | for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++) |
7118 | free_irq(phba->sli4_hba.msix_entries[index].vector, | 7125 | free_irq(phba->sli4_hba.msix_entries[index].vector, |
7119 | &phba->sli4_hba.fcp_eq_hdl[index - 1]); | 7126 | &phba->sli4_hba.fcp_eq_hdl[index - 1]); |
7127 | |||
7120 | /* Disable MSI-X */ | 7128 | /* Disable MSI-X */ |
7121 | pci_disable_msix(phba->pcidev); | 7129 | pci_disable_msix(phba->pcidev); |
7122 | 7130 | ||
@@ -7158,6 +7166,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) | |||
7158 | pci_disable_msi(phba->pcidev); | 7166 | pci_disable_msi(phba->pcidev); |
7159 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, | 7167 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, |
7160 | "0490 MSI request_irq failed (%d)\n", rc); | 7168 | "0490 MSI request_irq failed (%d)\n", rc); |
7169 | return rc; | ||
7161 | } | 7170 | } |
7162 | 7171 | ||
7163 | for (index = 0; index < phba->cfg_fcp_eq_count; index++) { | 7172 | for (index = 0; index < phba->cfg_fcp_eq_count; index++) { |
@@ -7165,7 +7174,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) | |||
7165 | phba->sli4_hba.fcp_eq_hdl[index].phba = phba; | 7174 | phba->sli4_hba.fcp_eq_hdl[index].phba = phba; |
7166 | } | 7175 | } |
7167 | 7176 | ||
7168 | return rc; | 7177 | return 0; |
7169 | } | 7178 | } |
7170 | 7179 | ||
7171 | /** | 7180 | /** |
@@ -7876,6 +7885,9 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) | |||
7876 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 7885 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, |
7877 | "2710 PCI channel disable preparing for reset\n"); | 7886 | "2710 PCI channel disable preparing for reset\n"); |
7878 | 7887 | ||
7888 | /* Block any management I/Os to the device */ | ||
7889 | lpfc_block_mgmt_io(phba); | ||
7890 | |||
7879 | /* Block all SCSI devices' I/Os on the host */ | 7891 | /* Block all SCSI devices' I/Os on the host */ |
7880 | lpfc_scsi_dev_block(phba); | 7892 | lpfc_scsi_dev_block(phba); |
7881 | 7893 | ||
@@ -7885,6 +7897,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) | |||
7885 | /* Disable interrupt and pci device */ | 7897 | /* Disable interrupt and pci device */ |
7886 | lpfc_sli_disable_intr(phba); | 7898 | lpfc_sli_disable_intr(phba); |
7887 | pci_disable_device(phba->pcidev); | 7899 | pci_disable_device(phba->pcidev); |
7900 | |||
7888 | /* Flush all driver's outstanding SCSI I/Os as we are to reset */ | 7901 | /* Flush all driver's outstanding SCSI I/Os as we are to reset */ |
7889 | lpfc_sli_flush_fcp_rings(phba); | 7902 | lpfc_sli_flush_fcp_rings(phba); |
7890 | } | 7903 | } |
@@ -7898,7 +7911,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) | |||
7898 | * pending I/Os. | 7911 | * pending I/Os. |
7899 | **/ | 7912 | **/ |
7900 | static void | 7913 | static void |
7901 | lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba) | 7914 | lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) |
7902 | { | 7915 | { |
7903 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 7916 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, |
7904 | "2711 PCI channel permanent disable for failure\n"); | 7917 | "2711 PCI channel permanent disable for failure\n"); |
@@ -7947,7 +7960,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) | |||
7947 | return PCI_ERS_RESULT_NEED_RESET; | 7960 | return PCI_ERS_RESULT_NEED_RESET; |
7948 | case pci_channel_io_perm_failure: | 7961 | case pci_channel_io_perm_failure: |
7949 | /* Permanent failure, prepare for device down */ | 7962 | /* Permanent failure, prepare for device down */ |
7950 | lpfc_prep_dev_for_perm_failure(phba); | 7963 | lpfc_sli_prep_dev_for_perm_failure(phba); |
7951 | return PCI_ERS_RESULT_DISCONNECT; | 7964 | return PCI_ERS_RESULT_DISCONNECT; |
7952 | default: | 7965 | default: |
7953 | /* Unknown state, prepare and request slot reset */ | 7966 | /* Unknown state, prepare and request slot reset */ |
@@ -8016,7 +8029,8 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev) | |||
8016 | } else | 8029 | } else |
8017 | phba->intr_mode = intr_mode; | 8030 | phba->intr_mode = intr_mode; |
8018 | 8031 | ||
8019 | /* Take device offline; this will perform cleanup */ | 8032 | /* Take device offline, it will perform cleanup */ |
8033 | lpfc_offline_prep(phba); | ||
8020 | lpfc_offline(phba); | 8034 | lpfc_offline(phba); |
8021 | lpfc_sli_brdrestart(phba); | 8035 | lpfc_sli_brdrestart(phba); |
8022 | 8036 | ||
@@ -8201,6 +8215,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
8201 | /* Default to single FCP EQ for non-MSI-X */ | 8215 | /* Default to single FCP EQ for non-MSI-X */ |
8202 | if (phba->intr_type != MSIX) | 8216 | if (phba->intr_type != MSIX) |
8203 | phba->cfg_fcp_eq_count = 1; | 8217 | phba->cfg_fcp_eq_count = 1; |
8218 | else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count) | ||
8219 | phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1; | ||
8204 | /* Set up SLI-4 HBA */ | 8220 | /* Set up SLI-4 HBA */ |
8205 | if (lpfc_sli4_hba_setup(phba)) { | 8221 | if (lpfc_sli4_hba_setup(phba)) { |
8206 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 8222 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, |
@@ -8362,7 +8378,7 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) | |||
8362 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | 8378 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; |
8363 | 8379 | ||
8364 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 8380 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
8365 | "0298 PCI device Power Management suspend.\n"); | 8381 | "2843 PCI device Power Management suspend.\n"); |
8366 | 8382 | ||
8367 | /* Bring down the device */ | 8383 | /* Bring down the device */ |
8368 | lpfc_offline_prep(phba); | 8384 | lpfc_offline_prep(phba); |
@@ -8453,6 +8469,84 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) | |||
8453 | } | 8469 | } |
8454 | 8470 | ||
8455 | /** | 8471 | /** |
8472 | * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover | ||
8473 | * @phba: pointer to lpfc hba data structure. | ||
8474 | * | ||
8475 | * This routine is called to prepare the SLI4 device for PCI slot recover. It | ||
8476 | * aborts all the outstanding SCSI I/Os to the pci device. | ||
8477 | **/ | ||
8478 | static void | ||
8479 | lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) | ||
8480 | { | ||
8481 | struct lpfc_sli *psli = &phba->sli; | ||
8482 | struct lpfc_sli_ring *pring; | ||
8483 | |||
8484 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8485 | "2828 PCI channel I/O abort preparing for recovery\n"); | ||
8486 | /* | ||
8487 | * There may be errored I/Os through HBA, abort all I/Os on txcmplq | ||
8488 | * and let the SCSI mid-layer to retry them to recover. | ||
8489 | */ | ||
8490 | pring = &psli->ring[psli->fcp_ring]; | ||
8491 | lpfc_sli_abort_iocb_ring(phba, pring); | ||
8492 | } | ||
8493 | |||
8494 | /** | ||
8495 | * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset | ||
8496 | * @phba: pointer to lpfc hba data structure. | ||
8497 | * | ||
8498 | * This routine is called to prepare the SLI4 device for PCI slot reset. It | ||
8499 | * disables the device interrupt and pci device, and aborts the internal FCP | ||
8500 | * pending I/Os. | ||
8501 | **/ | ||
8502 | static void | ||
8503 | lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) | ||
8504 | { | ||
8505 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8506 | "2826 PCI channel disable preparing for reset\n"); | ||
8507 | |||
8508 | /* Block any management I/Os to the device */ | ||
8509 | lpfc_block_mgmt_io(phba); | ||
8510 | |||
8511 | /* Block all SCSI devices' I/Os on the host */ | ||
8512 | lpfc_scsi_dev_block(phba); | ||
8513 | |||
8514 | /* stop all timers */ | ||
8515 | lpfc_stop_hba_timers(phba); | ||
8516 | |||
8517 | /* Disable interrupt and pci device */ | ||
8518 | lpfc_sli4_disable_intr(phba); | ||
8519 | pci_disable_device(phba->pcidev); | ||
8520 | |||
8521 | /* Flush all driver's outstanding SCSI I/Os as we are to reset */ | ||
8522 | lpfc_sli_flush_fcp_rings(phba); | ||
8523 | } | ||
8524 | |||
8525 | /** | ||
8526 | * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable | ||
8527 | * @phba: pointer to lpfc hba data structure. | ||
8528 | * | ||
8529 | * This routine is called to prepare the SLI4 device for PCI slot permanently | ||
8530 | * disabling. It blocks the SCSI transport layer traffic and flushes the FCP | ||
8531 | * pending I/Os. | ||
8532 | **/ | ||
8533 | static void | ||
8534 | lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) | ||
8535 | { | ||
8536 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8537 | "2827 PCI channel permanent disable for failure\n"); | ||
8538 | |||
8539 | /* Block all SCSI devices' I/Os on the host */ | ||
8540 | lpfc_scsi_dev_block(phba); | ||
8541 | |||
8542 | /* stop all timers */ | ||
8543 | lpfc_stop_hba_timers(phba); | ||
8544 | |||
8545 | /* Clean up all driver's outstanding SCSI I/Os */ | ||
8546 | lpfc_sli_flush_fcp_rings(phba); | ||
8547 | } | ||
8548 | |||
8549 | /** | ||
8456 | * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device | 8550 | * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device |
8457 | * @pdev: pointer to PCI device. | 8551 | * @pdev: pointer to PCI device. |
8458 | * @state: the current PCI connection state. | 8552 | * @state: the current PCI connection state. |
@@ -8471,7 +8565,29 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) | |||
8471 | static pci_ers_result_t | 8565 | static pci_ers_result_t |
8472 | lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) | 8566 | lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) |
8473 | { | 8567 | { |
8474 | return PCI_ERS_RESULT_NEED_RESET; | 8568 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
8569 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
8570 | |||
8571 | switch (state) { | ||
8572 | case pci_channel_io_normal: | ||
8573 | /* Non-fatal error, prepare for recovery */ | ||
8574 | lpfc_sli4_prep_dev_for_recover(phba); | ||
8575 | return PCI_ERS_RESULT_CAN_RECOVER; | ||
8576 | case pci_channel_io_frozen: | ||
8577 | /* Fatal error, prepare for slot reset */ | ||
8578 | lpfc_sli4_prep_dev_for_reset(phba); | ||
8579 | return PCI_ERS_RESULT_NEED_RESET; | ||
8580 | case pci_channel_io_perm_failure: | ||
8581 | /* Permanent failure, prepare for device down */ | ||
8582 | lpfc_sli4_prep_dev_for_perm_failure(phba); | ||
8583 | return PCI_ERS_RESULT_DISCONNECT; | ||
8584 | default: | ||
8585 | /* Unknown state, prepare and request slot reset */ | ||
8586 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8587 | "2825 Unknown PCI error state: x%x\n", state); | ||
8588 | lpfc_sli4_prep_dev_for_reset(phba); | ||
8589 | return PCI_ERS_RESULT_NEED_RESET; | ||
8590 | } | ||
8475 | } | 8591 | } |
8476 | 8592 | ||
8477 | /** | 8593 | /** |
@@ -8495,6 +8611,39 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) | |||
8495 | static pci_ers_result_t | 8611 | static pci_ers_result_t |
8496 | lpfc_io_slot_reset_s4(struct pci_dev *pdev) | 8612 | lpfc_io_slot_reset_s4(struct pci_dev *pdev) |
8497 | { | 8613 | { |
8614 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | ||
8615 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
8616 | struct lpfc_sli *psli = &phba->sli; | ||
8617 | uint32_t intr_mode; | ||
8618 | |||
8619 | dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); | ||
8620 | if (pci_enable_device_mem(pdev)) { | ||
8621 | printk(KERN_ERR "lpfc: Cannot re-enable " | ||
8622 | "PCI device after reset.\n"); | ||
8623 | return PCI_ERS_RESULT_DISCONNECT; | ||
8624 | } | ||
8625 | |||
8626 | pci_restore_state(pdev); | ||
8627 | if (pdev->is_busmaster) | ||
8628 | pci_set_master(pdev); | ||
8629 | |||
8630 | spin_lock_irq(&phba->hbalock); | ||
8631 | psli->sli_flag &= ~LPFC_SLI_ACTIVE; | ||
8632 | spin_unlock_irq(&phba->hbalock); | ||
8633 | |||
8634 | /* Configure and enable interrupt */ | ||
8635 | intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); | ||
8636 | if (intr_mode == LPFC_INTR_ERROR) { | ||
8637 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8638 | "2824 Cannot re-enable interrupt after " | ||
8639 | "slot reset.\n"); | ||
8640 | return PCI_ERS_RESULT_DISCONNECT; | ||
8641 | } else | ||
8642 | phba->intr_mode = intr_mode; | ||
8643 | |||
8644 | /* Log the current active interrupt mode */ | ||
8645 | lpfc_log_intr_mode(phba, phba->intr_mode); | ||
8646 | |||
8498 | return PCI_ERS_RESULT_RECOVERED; | 8647 | return PCI_ERS_RESULT_RECOVERED; |
8499 | } | 8648 | } |
8500 | 8649 | ||
@@ -8511,7 +8660,27 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) | |||
8511 | static void | 8660 | static void |
8512 | lpfc_io_resume_s4(struct pci_dev *pdev) | 8661 | lpfc_io_resume_s4(struct pci_dev *pdev) |
8513 | { | 8662 | { |
8514 | return; | 8663 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
8664 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; | ||
8665 | |||
8666 | /* | ||
8667 | * In case of slot reset, as function reset is performed through | ||
8668 | * mailbox command which needs DMA to be enabled, this operation | ||
8669 | * has to be moved to the io resume phase. Taking device offline | ||
8670 | * will perform the necessary cleanup. | ||
8671 | */ | ||
8672 | if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { | ||
8673 | /* Perform device reset */ | ||
8674 | lpfc_offline_prep(phba); | ||
8675 | lpfc_offline(phba); | ||
8676 | lpfc_sli_brdrestart(phba); | ||
8677 | /* Bring the device back online */ | ||
8678 | lpfc_online(phba); | ||
8679 | } | ||
8680 | |||
8681 | /* Clean up Advanced Error Reporting (AER) if needed */ | ||
8682 | if (phba->hba_flag & HBA_AER_ENABLED) | ||
8683 | pci_cleanup_aer_uncorrect_error_status(pdev); | ||
8515 | } | 8684 | } |
8516 | 8685 | ||
8517 | /** | 8686 | /** |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c6bdf63925d9..f68753ea941f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -2295,15 +2295,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
2295 | struct lpfc_vport *vport = pIocbIn->vport; | 2295 | struct lpfc_vport *vport = pIocbIn->vport; |
2296 | struct lpfc_rport_data *rdata = lpfc_cmd->rdata; | 2296 | struct lpfc_rport_data *rdata = lpfc_cmd->rdata; |
2297 | struct lpfc_nodelist *pnode = rdata->pnode; | 2297 | struct lpfc_nodelist *pnode = rdata->pnode; |
2298 | struct scsi_cmnd *cmd = lpfc_cmd->pCmd; | 2298 | struct scsi_cmnd *cmd; |
2299 | int result; | 2299 | int result; |
2300 | struct scsi_device *tmp_sdev; | 2300 | struct scsi_device *tmp_sdev; |
2301 | int depth; | 2301 | int depth; |
2302 | unsigned long flags; | 2302 | unsigned long flags; |
2303 | struct lpfc_fast_path_event *fast_path_evt; | 2303 | struct lpfc_fast_path_event *fast_path_evt; |
2304 | struct Scsi_Host *shost = cmd->device->host; | 2304 | struct Scsi_Host *shost; |
2305 | uint32_t queue_depth, scsi_id; | 2305 | uint32_t queue_depth, scsi_id; |
2306 | 2306 | ||
2307 | /* Sanity check on return of outstanding command */ | ||
2308 | if (!(lpfc_cmd->pCmd)) | ||
2309 | return; | ||
2310 | cmd = lpfc_cmd->pCmd; | ||
2311 | shost = cmd->device->host; | ||
2312 | |||
2307 | lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; | 2313 | lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; |
2308 | lpfc_cmd->status = pIocbOut->iocb.ulpStatus; | 2314 | lpfc_cmd->status = pIocbOut->iocb.ulpStatus; |
2309 | /* pick up SLI4 exhange busy status from HBA */ | 2315 | /* pick up SLI4 exhange busy status from HBA */ |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ae3cb0ab0ae4..9c609546b4ef 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -3593,13 +3593,16 @@ static int | |||
3593 | lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) | 3593 | lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) |
3594 | { | 3594 | { |
3595 | struct lpfc_sli *psli = &phba->sli; | 3595 | struct lpfc_sli *psli = &phba->sli; |
3596 | 3596 | uint32_t hba_aer_enabled; | |
3597 | 3597 | ||
3598 | /* Restart HBA */ | 3598 | /* Restart HBA */ |
3599 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, | 3599 | lpfc_printf_log(phba, KERN_INFO, LOG_SLI, |
3600 | "0296 Restart HBA Data: x%x x%x\n", | 3600 | "0296 Restart HBA Data: x%x x%x\n", |
3601 | phba->pport->port_state, psli->sli_flag); | 3601 | phba->pport->port_state, psli->sli_flag); |
3602 | 3602 | ||
3603 | /* Take PCIe device Advanced Error Reporting (AER) state */ | ||
3604 | hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; | ||
3605 | |||
3603 | lpfc_sli4_brdreset(phba); | 3606 | lpfc_sli4_brdreset(phba); |
3604 | 3607 | ||
3605 | spin_lock_irq(&phba->hbalock); | 3608 | spin_lock_irq(&phba->hbalock); |
@@ -3611,6 +3614,10 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) | |||
3611 | memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); | 3614 | memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); |
3612 | psli->stats_start = get_seconds(); | 3615 | psli->stats_start = get_seconds(); |
3613 | 3616 | ||
3617 | /* Reset HBA AER if it was enabled, note hba_flag was reset above */ | ||
3618 | if (hba_aer_enabled) | ||
3619 | pci_disable_pcie_error_reporting(phba->pcidev); | ||
3620 | |||
3614 | lpfc_hba_down_post(phba); | 3621 | lpfc_hba_down_post(phba); |
3615 | 3622 | ||
3616 | return 0; | 3623 | return 0; |
@@ -4554,6 +4561,24 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) | |||
4554 | /* Start error attention (ERATT) polling timer */ | 4561 | /* Start error attention (ERATT) polling timer */ |
4555 | mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); | 4562 | mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); |
4556 | 4563 | ||
4564 | /* Enable PCIe device Advanced Error Reporting (AER) if configured */ | ||
4565 | if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { | ||
4566 | rc = pci_enable_pcie_error_reporting(phba->pcidev); | ||
4567 | if (!rc) { | ||
4568 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
4569 | "2829 This device supports " | ||
4570 | "Advanced Error Reporting (AER)\n"); | ||
4571 | spin_lock_irq(&phba->hbalock); | ||
4572 | phba->hba_flag |= HBA_AER_ENABLED; | ||
4573 | spin_unlock_irq(&phba->hbalock); | ||
4574 | } else { | ||
4575 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
4576 | "2830 This device does not support " | ||
4577 | "Advanced Error Reporting (AER)\n"); | ||
4578 | phba->cfg_aer_support = 0; | ||
4579 | } | ||
4580 | } | ||
4581 | |||
4557 | /* | 4582 | /* |
4558 | * The port is ready, set the host's link state to LINK_DOWN | 4583 | * The port is ready, set the host's link state to LINK_DOWN |
4559 | * in preparation for link interrupts. | 4584 | * in preparation for link interrupts. |
@@ -9089,9 +9114,10 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) | |||
9089 | } | 9114 | } |
9090 | } | 9115 | } |
9091 | if (unlikely(!cq)) { | 9116 | if (unlikely(!cq)) { |
9092 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | 9117 | if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) |
9093 | "0365 Slow-path CQ identifier (%d) does " | 9118 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
9094 | "not exist\n", cqid); | 9119 | "0365 Slow-path CQ identifier " |
9120 | "(%d) does not exist\n", cqid); | ||
9095 | return; | 9121 | return; |
9096 | } | 9122 | } |
9097 | 9123 | ||
@@ -9321,9 +9347,10 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, | |||
9321 | 9347 | ||
9322 | cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; | 9348 | cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; |
9323 | if (unlikely(!cq)) { | 9349 | if (unlikely(!cq)) { |
9324 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | 9350 | if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) |
9325 | "0367 Fast-path completion queue does not " | 9351 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
9326 | "exist\n"); | 9352 | "0367 Fast-path completion queue " |
9353 | "does not exist\n"); | ||
9327 | return; | 9354 | return; |
9328 | } | 9355 | } |
9329 | 9356 | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 1f8ec72c5dcb..ccdb95774e84 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h | |||
@@ -382,6 +382,7 @@ struct lpfc_sli4_hba { | |||
382 | struct lpfc_pc_sli4_params pc_sli4_params; | 382 | struct lpfc_pc_sli4_params pc_sli4_params; |
383 | struct msix_entry *msix_entries; | 383 | struct msix_entry *msix_entries; |
384 | uint32_t cfg_eqn; | 384 | uint32_t cfg_eqn; |
385 | uint32_t msix_vec_nr; | ||
385 | struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ | 386 | struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ |
386 | /* Pointers to the constructed SLI4 queues */ | 387 | /* Pointers to the constructed SLI4 queues */ |
387 | struct lpfc_queue **fp_eq; /* Fast-path event queue */ | 388 | struct lpfc_queue **fp_eq; /* Fast-path event queue */ |