Loading drivers/scsi/lpfc/lpfc_crtn.h +2 −0 Original line number Diff line number Diff line Loading @@ -199,6 +199,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *, uint32_t); void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *); struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, Loading Loading @@ -290,6 +291,7 @@ void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); void lpfc_adjust_queue_depth(struct lpfc_hba *); void lpfc_ramp_down_queue_handler(struct lpfc_hba *); void lpfc_ramp_up_queue_handler(struct lpfc_hba *); void lpfc_scsi_dev_block(struct lpfc_hba *); #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) #define HBA_EVENT_RSCN 5 Loading drivers/scsi/lpfc/lpfc_hbadisc.c +0 −2 Original line number Diff line number Diff line Loading @@ -237,8 +237,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], ndlp->nlp_sid, 0, LPFC_CTX_TGT); } if (vport->load_flag & FC_UNLOADING) warn_on = 0; if (warn_on) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, Loading drivers/scsi/lpfc/lpfc_init.c +8 −1 Original line number Diff line number Diff line Loading @@ -2661,8 +2661,15 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; if (state == pci_channel_io_perm_failure) if (state == pci_channel_io_perm_failure) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0472 PCI channel I/O permanent failure\n"); /* Block all SCSI devices' I/Os on the host */ lpfc_scsi_dev_block(phba); /* Clean up all driver's outstanding SCSI I/Os */ lpfc_sli_flush_fcp_rings(phba); return PCI_ERS_RESULT_DISCONNECT; } pci_disable_device(pdev); /* Loading drivers/scsi/lpfc/lpfc_scsi.c +29 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,35 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) atomic_set(&phba->num_cmd_success, 0); } /** * lpfc_scsi_dev_block: set all scsi hosts to block state. * @phba: Pointer to HBA context object. * * This function walks vport list and set each SCSI host to block state * by invoking fc_remote_port_delete() routine. This function is invoked * with EEH when device's PCI slot has been permanently disabled. **/ void lpfc_scsi_dev_block(struct lpfc_hba *phba) { struct lpfc_vport **vports; struct Scsi_Host *shost; struct scsi_device *sdev; struct fc_rport *rport; int i; vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { rport = starget_to_rport(scsi_target(sdev)); fc_remote_port_delete(rport); } } lpfc_destroy_vport_work_array(phba, vports); } /* * This routine allocates a scsi buffer, which contains all the necessary * information needed to initiate a SCSI I/O. The non-DMAable buffer region Loading drivers/scsi/lpfc/lpfc_sli.c +64 −0 Original line number Diff line number Diff line Loading @@ -2376,6 +2376,70 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) } } /** * lpfc_sli_flush_fcp_rings: flush all iocbs in the fcp ring. * @phba: Pointer to HBA context object. * * This function flushes all iocbs in the fcp ring and frees all the iocb * objects in txq and txcmplq. This function will not issue abort iocbs * for all the iocb commands in txcmplq, they will just be returned with * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI * slot has been permanently disabled. **/ void lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) { LIST_HEAD(txq); LIST_HEAD(txcmplq); struct lpfc_iocbq *iocb; IOCB_t *cmd = NULL; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; /* Currently, only one fcp ring */ pring = &psli->ring[psli->fcp_ring]; spin_lock_irq(&phba->hbalock); /* Retrieve everything on txq */ list_splice_init(&pring->txq, &txq); pring->txq_cnt = 0; /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txcmplq_cnt = 0; spin_unlock_irq(&phba->hbalock); /* Flush the txq */ while (!list_empty(&txq)) { iocb = list_get_first(&txq, struct lpfc_iocbq, list); cmd = &iocb->iocb; list_del_init(&iocb->list); if (!iocb->iocb_cmpl) lpfc_sli_release_iocbq(phba, iocb); else { cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_DOWN; (iocb->iocb_cmpl) (phba, iocb, iocb); } } /* Flush the txcmpq */ while (!list_empty(&txcmplq)) { iocb = list_get_first(&txcmplq, struct lpfc_iocbq, list); cmd = &iocb->iocb; list_del_init(&iocb->list); if (!iocb->iocb_cmpl) lpfc_sli_release_iocbq(phba, iocb); else { cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_DOWN; (iocb->iocb_cmpl) (phba, iocb, iocb); } } } /** * lpfc_sli_brdready: Check for host status bits. * @phba: Pointer to HBA context object. Loading Loading
drivers/scsi/lpfc/lpfc_crtn.h +2 −0 Original line number Diff line number Diff line Loading @@ -199,6 +199,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *, uint32_t); void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *); struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, Loading Loading @@ -290,6 +291,7 @@ void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); void lpfc_adjust_queue_depth(struct lpfc_hba *); void lpfc_ramp_down_queue_handler(struct lpfc_hba *); void lpfc_ramp_up_queue_handler(struct lpfc_hba *); void lpfc_scsi_dev_block(struct lpfc_hba *); #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) #define HBA_EVENT_RSCN 5 Loading
drivers/scsi/lpfc/lpfc_hbadisc.c +0 −2 Original line number Diff line number Diff line Loading @@ -237,8 +237,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], ndlp->nlp_sid, 0, LPFC_CTX_TGT); } if (vport->load_flag & FC_UNLOADING) warn_on = 0; if (warn_on) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, Loading
drivers/scsi/lpfc/lpfc_init.c +8 −1 Original line number Diff line number Diff line Loading @@ -2661,8 +2661,15 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; if (state == pci_channel_io_perm_failure) if (state == pci_channel_io_perm_failure) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0472 PCI channel I/O permanent failure\n"); /* Block all SCSI devices' I/Os on the host */ lpfc_scsi_dev_block(phba); /* Clean up all driver's outstanding SCSI I/Os */ lpfc_sli_flush_fcp_rings(phba); return PCI_ERS_RESULT_DISCONNECT; } pci_disable_device(pdev); /* Loading
drivers/scsi/lpfc/lpfc_scsi.c +29 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,35 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) atomic_set(&phba->num_cmd_success, 0); } /** * lpfc_scsi_dev_block: set all scsi hosts to block state. * @phba: Pointer to HBA context object. * * This function walks vport list and set each SCSI host to block state * by invoking fc_remote_port_delete() routine. This function is invoked * with EEH when device's PCI slot has been permanently disabled. **/ void lpfc_scsi_dev_block(struct lpfc_hba *phba) { struct lpfc_vport **vports; struct Scsi_Host *shost; struct scsi_device *sdev; struct fc_rport *rport; int i; vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { rport = starget_to_rport(scsi_target(sdev)); fc_remote_port_delete(rport); } } lpfc_destroy_vport_work_array(phba, vports); } /* * This routine allocates a scsi buffer, which contains all the necessary * information needed to initiate a SCSI I/O. The non-DMAable buffer region Loading
drivers/scsi/lpfc/lpfc_sli.c +64 −0 Original line number Diff line number Diff line Loading @@ -2376,6 +2376,70 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) } } /** * lpfc_sli_flush_fcp_rings: flush all iocbs in the fcp ring. * @phba: Pointer to HBA context object. * * This function flushes all iocbs in the fcp ring and frees all the iocb * objects in txq and txcmplq. This function will not issue abort iocbs * for all the iocb commands in txcmplq, they will just be returned with * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI * slot has been permanently disabled. **/ void lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) { LIST_HEAD(txq); LIST_HEAD(txcmplq); struct lpfc_iocbq *iocb; IOCB_t *cmd = NULL; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; /* Currently, only one fcp ring */ pring = &psli->ring[psli->fcp_ring]; spin_lock_irq(&phba->hbalock); /* Retrieve everything on txq */ list_splice_init(&pring->txq, &txq); pring->txq_cnt = 0; /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txcmplq_cnt = 0; spin_unlock_irq(&phba->hbalock); /* Flush the txq */ while (!list_empty(&txq)) { iocb = list_get_first(&txq, struct lpfc_iocbq, list); cmd = &iocb->iocb; list_del_init(&iocb->list); if (!iocb->iocb_cmpl) lpfc_sli_release_iocbq(phba, iocb); else { cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_DOWN; (iocb->iocb_cmpl) (phba, iocb, iocb); } } /* Flush the txcmpq */ while (!list_empty(&txcmplq)) { iocb = list_get_first(&txcmplq, struct lpfc_iocbq, list); cmd = &iocb->iocb; list_del_init(&iocb->list); if (!iocb->iocb_cmpl) lpfc_sli_release_iocbq(phba, iocb); else { cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_DOWN; (iocb->iocb_cmpl) (phba, iocb, iocb); } } } /** * lpfc_sli_brdready: Check for host status bits. * @phba: Pointer to HBA context object. Loading