diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-08-24 21:50:11 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-10-13 09:28:54 -0400 |
commit | a8e497d51e6adb2dd6ef307ae76f3433a4dbe895 (patch) | |
tree | 35c1a66bcd2fc8903cc7f25cfbafb919f5cd7b9a /drivers/scsi/lpfc | |
parent | 84774a4d0a4dba8a5767da6c58ea5a8c5b0cfe25 (diff) |
[SCSI] lpfc 8.2.8 : Add support for PCI-EEH permanent disabling
Add support for PCI-EEH permanent-disabling a device via lpfc_pci_remove_one()
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 9 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 29 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 64 |
5 files changed, 103 insertions, 3 deletions
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 189ce9f8a7b1..495afd06936b 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -199,6 +199,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, | |||
199 | struct lpfc_iocbq *, uint32_t); | 199 | struct lpfc_iocbq *, uint32_t); |
200 | void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); | 200 | void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); |
201 | void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); | 201 | void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); |
202 | void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); | ||
202 | int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, | 203 | int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, |
203 | struct lpfc_dmabuf *); | 204 | struct lpfc_dmabuf *); |
204 | struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, | 205 | struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, |
@@ -290,6 +291,7 @@ void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); | |||
290 | void lpfc_adjust_queue_depth(struct lpfc_hba *); | 291 | void lpfc_adjust_queue_depth(struct lpfc_hba *); |
291 | void lpfc_ramp_down_queue_handler(struct lpfc_hba *); | 292 | void lpfc_ramp_down_queue_handler(struct lpfc_hba *); |
292 | void lpfc_ramp_up_queue_handler(struct lpfc_hba *); | 293 | void lpfc_ramp_up_queue_handler(struct lpfc_hba *); |
294 | void lpfc_scsi_dev_block(struct lpfc_hba *); | ||
293 | 295 | ||
294 | #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) | 296 | #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) |
295 | #define HBA_EVENT_RSCN 5 | 297 | #define HBA_EVENT_RSCN 5 |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index b4ef83623532..897ef7d7a8e9 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -237,8 +237,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
237 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], | 237 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], |
238 | ndlp->nlp_sid, 0, LPFC_CTX_TGT); | 238 | ndlp->nlp_sid, 0, LPFC_CTX_TGT); |
239 | } | 239 | } |
240 | if (vport->load_flag & FC_UNLOADING) | ||
241 | warn_on = 0; | ||
242 | 240 | ||
243 | if (warn_on) { | 241 | if (warn_on) { |
244 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 242 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 41a8c13e6950..333166b17908 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -2661,8 +2661,15 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, | |||
2661 | struct lpfc_sli *psli = &phba->sli; | 2661 | struct lpfc_sli *psli = &phba->sli; |
2662 | struct lpfc_sli_ring *pring; | 2662 | struct lpfc_sli_ring *pring; |
2663 | 2663 | ||
2664 | if (state == pci_channel_io_perm_failure) | 2664 | if (state == pci_channel_io_perm_failure) { |
2665 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
2666 | "0472 PCI channel I/O permanent failure\n"); | ||
2667 | /* Block all SCSI devices' I/Os on the host */ | ||
2668 | lpfc_scsi_dev_block(phba); | ||
2669 | /* Clean up all driver's outstanding SCSI I/Os */ | ||
2670 | lpfc_sli_flush_fcp_rings(phba); | ||
2665 | return PCI_ERS_RESULT_DISCONNECT; | 2671 | return PCI_ERS_RESULT_DISCONNECT; |
2672 | } | ||
2666 | 2673 | ||
2667 | pci_disable_device(pdev); | 2674 | pci_disable_device(pdev); |
2668 | /* | 2675 | /* |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index b73968b2b8b4..3606b7098fc1 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -183,6 +183,35 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) | |||
183 | atomic_set(&phba->num_cmd_success, 0); | 183 | atomic_set(&phba->num_cmd_success, 0); |
184 | } | 184 | } |
185 | 185 | ||
186 | /** | ||
187 | * lpfc_scsi_dev_block: set all scsi hosts to block state. | ||
188 | * @phba: Pointer to HBA context object. | ||
189 | * | ||
190 | * This function walks vport list and set each SCSI host to block state | ||
191 | * by invoking fc_remote_port_delete() routine. This function is invoked | ||
192 | * with EEH when device's PCI slot has been permanently disabled. | ||
193 | **/ | ||
194 | void | ||
195 | lpfc_scsi_dev_block(struct lpfc_hba *phba) | ||
196 | { | ||
197 | struct lpfc_vport **vports; | ||
198 | struct Scsi_Host *shost; | ||
199 | struct scsi_device *sdev; | ||
200 | struct fc_rport *rport; | ||
201 | int i; | ||
202 | |||
203 | vports = lpfc_create_vport_work_array(phba); | ||
204 | if (vports != NULL) | ||
205 | for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { | ||
206 | shost = lpfc_shost_from_vport(vports[i]); | ||
207 | shost_for_each_device(sdev, shost) { | ||
208 | rport = starget_to_rport(scsi_target(sdev)); | ||
209 | fc_remote_port_delete(rport); | ||
210 | } | ||
211 | } | ||
212 | lpfc_destroy_vport_work_array(phba, vports); | ||
213 | } | ||
214 | |||
186 | /* | 215 | /* |
187 | * This routine allocates a scsi buffer, which contains all the necessary | 216 | * This routine allocates a scsi buffer, which contains all the necessary |
188 | * information needed to initiate a SCSI I/O. The non-DMAable buffer region | 217 | * information needed to initiate a SCSI I/O. The non-DMAable buffer region |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 857bc0a57c47..1812e18246d5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -2377,6 +2377,70 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) | |||
2377 | } | 2377 | } |
2378 | 2378 | ||
2379 | /** | 2379 | /** |
2380 | * lpfc_sli_flush_fcp_rings: flush all iocbs in the fcp ring. | ||
2381 | * @phba: Pointer to HBA context object. | ||
2382 | * | ||
2383 | * This function flushes all iocbs in the fcp ring and frees all the iocb | ||
2384 | * objects in txq and txcmplq. This function will not issue abort iocbs | ||
2385 | * for all the iocb commands in txcmplq, they will just be returned with | ||
2386 | * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI | ||
2387 | * slot has been permanently disabled. | ||
2388 | **/ | ||
2389 | void | ||
2390 | lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) | ||
2391 | { | ||
2392 | LIST_HEAD(txq); | ||
2393 | LIST_HEAD(txcmplq); | ||
2394 | struct lpfc_iocbq *iocb; | ||
2395 | IOCB_t *cmd = NULL; | ||
2396 | struct lpfc_sli *psli = &phba->sli; | ||
2397 | struct lpfc_sli_ring *pring; | ||
2398 | |||
2399 | /* Currently, only one fcp ring */ | ||
2400 | pring = &psli->ring[psli->fcp_ring]; | ||
2401 | |||
2402 | spin_lock_irq(&phba->hbalock); | ||
2403 | /* Retrieve everything on txq */ | ||
2404 | list_splice_init(&pring->txq, &txq); | ||
2405 | pring->txq_cnt = 0; | ||
2406 | |||
2407 | /* Retrieve everything on the txcmplq */ | ||
2408 | list_splice_init(&pring->txcmplq, &txcmplq); | ||
2409 | pring->txcmplq_cnt = 0; | ||
2410 | spin_unlock_irq(&phba->hbalock); | ||
2411 | |||
2412 | /* Flush the txq */ | ||
2413 | while (!list_empty(&txq)) { | ||
2414 | iocb = list_get_first(&txq, struct lpfc_iocbq, list); | ||
2415 | cmd = &iocb->iocb; | ||
2416 | list_del_init(&iocb->list); | ||
2417 | |||
2418 | if (!iocb->iocb_cmpl) | ||
2419 | lpfc_sli_release_iocbq(phba, iocb); | ||
2420 | else { | ||
2421 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
2422 | cmd->un.ulpWord[4] = IOERR_SLI_DOWN; | ||
2423 | (iocb->iocb_cmpl) (phba, iocb, iocb); | ||
2424 | } | ||
2425 | } | ||
2426 | |||
2427 | /* Flush the txcmpq */ | ||
2428 | while (!list_empty(&txcmplq)) { | ||
2429 | iocb = list_get_first(&txcmplq, struct lpfc_iocbq, list); | ||
2430 | cmd = &iocb->iocb; | ||
2431 | list_del_init(&iocb->list); | ||
2432 | |||
2433 | if (!iocb->iocb_cmpl) | ||
2434 | lpfc_sli_release_iocbq(phba, iocb); | ||
2435 | else { | ||
2436 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
2437 | cmd->un.ulpWord[4] = IOERR_SLI_DOWN; | ||
2438 | (iocb->iocb_cmpl) (phba, iocb, iocb); | ||
2439 | } | ||
2440 | } | ||
2441 | } | ||
2442 | |||
2443 | /** | ||
2380 | * lpfc_sli_brdready: Check for host status bits. | 2444 | * lpfc_sli_brdready: Check for host status bits. |
2381 | * @phba: Pointer to HBA context object. | 2445 | * @phba: Pointer to HBA context object. |
2382 | * @mask: Bit mask to be checked. | 2446 | * @mask: Bit mask to be checked. |