diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 96 |
1 files changed, 72 insertions, 24 deletions
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 | **/ | ||
7144 | static void | ||
7145 | lpfc_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 | **/ | ||
7172 | static void | ||
7173 | lpfc_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 | /** |