diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 493 |
1 files changed, 381 insertions, 112 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ea44239eeb3..2786ee3b605 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -29,6 +29,7 @@ #include <linux/spinlock.h> #include <linux/ctype.h> #include <linux/aer.h> +#include <linux/slab.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> @@ -620,6 +621,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) /** * lpfc_hba_init_link - Initialize the FC link * @phba: pointer to lpfc hba data structure. + * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the INIT_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data @@ -631,7 +633,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) * Any other value - error **/ int -lpfc_hba_init_link(struct lpfc_hba *phba) +lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) { struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *pmb; @@ -650,7 +652,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba) phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; lpfc_set_loopback_flag(phba); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + rc = lpfc_sli_issue_mbox(phba, pmb, flag); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0498 Adapter failed to init, mbxCmd x%x " @@ -663,17 +665,21 @@ lpfc_hba_init_link(struct lpfc_hba *phba) writel(0xffffffff, phba->HAregaddr); readl(phba->HAregaddr); /* flush */ phba->link_state = LPFC_HBA_ERROR; - if (rc != MBX_BUSY) + if (rc != MBX_BUSY || flag == MBX_POLL) mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK; + if (flag == MBX_POLL) + mempool_free(pmb, phba->mbox_mem_pool); return 0; } /** * lpfc_hba_down_link - this routine downs the FC link + * @phba: pointer to lpfc hba data structure. + * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the DOWN_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data @@ -684,7 +690,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba) * Any other value - error **/ int -lpfc_hba_down_link(struct lpfc_hba *phba) +lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag) { LPFC_MBOXQ_t *pmb; int rc; @@ -700,7 +706,7 @@ lpfc_hba_down_link(struct lpfc_hba *phba) "0491 Adapter Link is disabled.\n"); lpfc_down_link(phba, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + rc = lpfc_sli_issue_mbox(phba, pmb, flag); if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -710,6 +716,9 @@ lpfc_hba_down_link(struct lpfc_hba *phba) mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } + if (flag == MBX_POLL) + mempool_free(pmb, phba->mbox_mem_pool); + return 0; } @@ -1817,6 +1826,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"LPSe12002-ML1-E", "PCIe", "EmulexSecure Fibre"}; break; + case PCI_DEVICE_ID_BALIUS: + m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", + "Fibre Channel Adapter"}; + break; default: m = (typeof(m)){"Unknown", "", ""}; break; @@ -2278,10 +2291,32 @@ static void lpfc_block_mgmt_io(struct lpfc_hba * phba) { unsigned long iflag; + uint8_t actcmd = MBX_HEARTBEAT; + unsigned long timeout; + spin_lock_irqsave(&phba->hbalock, iflag); phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO; + if (phba->sli.mbox_active) + actcmd = phba->sli.mbox_active->u.mb.mbxCommand; spin_unlock_irqrestore(&phba->hbalock, iflag); + /* Determine how long we might wait for the active mailbox + * command to be gracefully completed by firmware. + */ + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) + + jiffies; + /* Wait for the outstnading mailbox command to complete */ + while (phba->sli.mbox_active) { + /* Check active mailbox complete status every 2ms */ + msleep(2); + if (time_after(jiffies, timeout)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2813 Mgmt IO is Blocked %x " + "- mbox cmd %x still active\n", + phba->sli.sli_flag, actcmd); + break; + } + } } /** @@ -2565,7 +2600,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) shost->max_cmd_len = 16; if (phba->sli_rev == LPFC_SLI_REV4) { shost->dma_boundary = - phba->sli4_hba.pc_sli4_params.sge_supp_len; + phba->sli4_hba.pc_sli4_params.sge_supp_len-1; shost->sg_tablesize = phba->cfg_sg_seg_cnt; } @@ -2599,15 +2634,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) init_timer(&vport->els_tmofunc); vport->els_tmofunc.function = lpfc_els_timeout; vport->els_tmofunc.data = (unsigned long)vport; - if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) { - phba->menlo_flag |= HBA_MENLO_SUPPORT; - /* check for menlo minimum sg count */ - if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) { - phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT; - shost->sg_tablesize = phba->cfg_sg_seg_cnt; - } - } - error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); if (error) goto out_put_shost; @@ -3235,12 +3261,26 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) if (!vport) return NULL; - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) - return NULL; phba = vport->phba; if (!phba) return NULL; + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) { + /* Cannot find existing Fabric ndlp, so allocate a new one */ + ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); + if (!ndlp) + return 0; + lpfc_nlp_init(vport, ndlp, Fabric_DID); + /* Set the node type */ + ndlp->nlp_type |= NLP_FABRIC; + /* Put ndlp onto node list */ + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + /* re-setup ndlp without removing from node list */ + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return 0; + } if (phba->pport->port_state <= LPFC_FLOGI) return NULL; /* If virtual link is not yet instantiated ignore CVL */ @@ -3303,27 +3343,28 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, switch (event_type) { case LPFC_FCOE_EVENT_TYPE_NEW_FCF: case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD: - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, - "2546 New FCF found/FCF parameter modified event: " - "evt_tag:x%x, fcf_index:x%x\n", - acqe_fcoe->event_tag, acqe_fcoe->index); - + if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF) + lpfc_printf_log(phba, KERN_ERR, LOG_FIP | + LOG_DISCOVERY, + "2546 New FCF found event: " + "evt_tag:x%x, fcf_index:x%x\n", + acqe_fcoe->event_tag, + acqe_fcoe->index); + else + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | + LOG_DISCOVERY, + "2788 FCF parameter modified event: " + "evt_tag:x%x, fcf_index:x%x\n", + acqe_fcoe->event_tag, + acqe_fcoe->index); + /* If the FCF discovery is in progress, do nothing. */ spin_lock_irq(&phba->hbalock); - if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) || - (phba->hba_flag & FCF_DISC_INPROGRESS)) { - /* - * If the current FCF is in discovered state or - * FCF discovery is in progress, do nothing. - */ + if (phba->hba_flag & FCF_DISC_INPROGRESS) { spin_unlock_irq(&phba->hbalock); break; } - + /* If fast FCF failover rescan event is pending, do nothing */ if (phba->fcf.fcf_flag & FCF_REDISC_EVT) { - /* - * If fast FCF failover rescan event is pending, - * do nothing. - */ spin_unlock_irq(&phba->hbalock); break; } @@ -3344,7 +3385,13 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, acqe_fcoe->index); rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index); } - + /* If the FCF has been in discovered state, do nothing. */ + spin_lock_irq(&phba->hbalock); + if (phba->fcf.fcf_flag & FCF_SCAN_DONE) { + spin_unlock_irq(&phba->hbalock); + break; + } + spin_unlock_irq(&phba->hbalock); /* Otherwise, scan the entire FCF table and re-discover SAN */ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, "2770 Start FCF table scan due to new FCF " @@ -3516,6 +3563,32 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba, } /** + * lpfc_sli4_async_grp5_evt - Process the asynchronous group5 event + * @phba: pointer to lpfc hba data structure. + * @acqe_link: pointer to the async grp5 completion queue entry. + * + * This routine is to handle the SLI4 asynchronous grp5 event. A grp5 event + * is an asynchronous notified of a logical link speed change. The Port + * reports the logical link speed in units of 10Mbps. + **/ +static void +lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, + struct lpfc_acqe_grp5 *acqe_grp5) +{ + uint16_t prev_ll_spd; + + phba->fc_eventTag = acqe_grp5->event_tag; + phba->fcoe_eventtag = acqe_grp5->event_tag; + prev_ll_spd = phba->sli4_hba.link_state.logical_speed; + phba->sli4_hba.link_state.logical_speed = + (bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5)); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2789 GRP5 Async Event: Updating logical link speed " + "from %dMbps to %dMbps\n", (prev_ll_spd * 10), + (phba->sli4_hba.link_state.logical_speed*10)); +} + +/** * lpfc_sli4_async_event_proc - Process all the pending asynchronous event * @phba: pointer to lpfc hba data structure. * @@ -3551,6 +3624,10 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) lpfc_sli4_async_dcbx_evt(phba, &cq_event->cqe.acqe_dcbx); break; + case LPFC_TRAILER_CODE_GRP5: + lpfc_sli4_async_grp5_evt(phba, + &cq_event->cqe.acqe_grp5); + break; default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "1804 Invalid asynchrous event code: " @@ -3812,6 +3889,13 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) /* Get all the module params for configuring this host */ lpfc_get_cfgparam(phba); + if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) { + phba->menlo_flag |= HBA_MENLO_SUPPORT; + /* check for menlo minimum sg count */ + if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) + phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT; + } + /* * Since the sg_tablesize is module parameter, the sg_dma_buf_size * used to create the sg_dma_buf_pool must be dynamically calculated. @@ -4029,6 +4113,43 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (unlikely(rc)) goto out_free_bsmbx; + mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!mboxq) { + rc = -ENOMEM; + goto out_free_bsmbx; + } + + /* Get the Supported Pages. It is always available. */ + lpfc_supported_pages(mboxq); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + if (unlikely(rc)) { + rc = -EIO; + mempool_free(mboxq, phba->mbox_mem_pool); + goto out_free_bsmbx; + } + + mqe = &mboxq->u.mqe; + memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3), + LPFC_MAX_SUPPORTED_PAGES); + for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) { + switch (pn_page[i]) { + case LPFC_SLI4_PARAMETERS: + phba->sli4_hba.pc_sli4_params.supported = 1; + break; + default: + break; + } + } + + /* Read the port's SLI4 Parameters capabilities if supported. */ + if (phba->sli4_hba.pc_sli4_params.supported) + rc = lpfc_pc_sli4_params_get(phba, mboxq); + mempool_free(mboxq, phba->mbox_mem_pool); + if (rc) { + rc = -EIO; + goto out_free_bsmbx; + } /* Create all the SLI4 queues */ rc = lpfc_sli4_queue_create(phba); if (rc) @@ -4089,43 +4210,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) goto out_free_fcp_eq_hdl; } - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!mboxq) { - rc = -ENOMEM; - goto out_free_fcp_eq_hdl; - } - - /* Get the Supported Pages. It is always available. */ - lpfc_supported_pages(mboxq); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (unlikely(rc)) { - rc = -EIO; - mempool_free(mboxq, phba->mbox_mem_pool); - goto out_free_fcp_eq_hdl; - } - - mqe = &mboxq->u.mqe; - memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3), - LPFC_MAX_SUPPORTED_PAGES); - for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) { - switch (pn_page[i]) { - case LPFC_SLI4_PARAMETERS: - phba->sli4_hba.pc_sli4_params.supported = 1; - break; - default: - break; - } - } - - /* Read the port's SLI4 Parameters capabilities if supported. */ - if (phba->sli4_hba.pc_sli4_params.supported) - rc = lpfc_pc_sli4_params_get(phba, mboxq); - mempool_free(mboxq, phba->mbox_mem_pool); - if (rc) { - rc = -EIO; - goto out_free_fcp_eq_hdl; - } return rc; out_free_fcp_eq_hdl: @@ -4833,6 +4917,7 @@ lpfc_create_shost(struct lpfc_hba *phba) phba->fc_altov = FF_DEF_ALTOV; phba->fc_arbtov = FF_DEF_ARBTOV; + atomic_set(&phba->sdev_cnt, 0); vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); if (!vport) return -ENODEV; @@ -5049,6 +5134,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba) memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); + phba->mbox_ext = (phba->slim2p.virt + + offsetof(struct lpfc_sli2_slim, mbx_ext_words)); phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); phba->IOCBs = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, IOCBs)); @@ -5479,9 +5566,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) mempool_free(pmb, phba->mbox_mem_pool); /* Reset the DFT_HBA_Q_DEPTH to the max xri */ - if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri)) + if (phba->cfg_hba_queue_depth > + (phba->sli4_hba.max_cfg_param.max_xri - + lpfc_sli4_get_els_iocb_cnt(phba))) phba->cfg_hba_queue_depth = - phba->sli4_hba.max_cfg_param.max_xri; + phba->sli4_hba.max_cfg_param.max_xri - + lpfc_sli4_get_els_iocb_cnt(phba); return rc; } @@ -6939,22 +7029,28 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba) static int lpfc_sli4_enable_msix(struct lpfc_hba *phba) { - int rc, index; + int vectors, rc, index; /* Set up MSI-X multi-message vectors */ for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) phba->sli4_hba.msix_entries[index].entry = index; /* Configure MSI-X capability structure */ + vectors = phba->sli4_hba.cfg_eqn; +enable_msix_vectors: rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries, - phba->sli4_hba.cfg_eqn); - if (rc) { + vectors); + if (rc > 1) { + vectors = rc; + goto enable_msix_vectors; + } else if (rc) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0484 PCI enable MSI-X failed (%d)\n", rc); goto msi_fail_out; } + /* Log MSI-X vector assignment */ - for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) + for (index = 0; index < vectors; index++) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0489 MSI-X entry[%d]: vector=x%x " "message=%d\n", index, @@ -6976,7 +7072,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) } /* The rest of the vector(s) are associated to fast-path handler(s) */ - for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) { + for (index = 1; index < vectors; index++) { phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1; phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba; rc = request_irq(phba->sli4_hba.msix_entries[index].vector, @@ -6990,6 +7086,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) goto cfg_fail_out; } } + phba->sli4_hba.msix_vec_nr = vectors; return rc; @@ -7023,9 +7120,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba) /* Free up MSI-X multi-message vectors */ free_irq(phba->sli4_hba.msix_entries[0].vector, phba); - for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) + for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++) free_irq(phba->sli4_hba.msix_entries[index].vector, &phba->sli4_hba.fcp_eq_hdl[index - 1]); + /* Disable MSI-X */ pci_disable_msix(phba->pcidev); @@ -7067,6 +7165,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) pci_disable_msi(phba->pcidev); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0490 MSI request_irq failed (%d)\n", rc); + return rc; } for (index = 0; index < phba->cfg_fcp_eq_count; index++) { @@ -7074,7 +7173,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) phba->sli4_hba.fcp_eq_hdl[index].phba = phba; } - return rc; + return 0; } /** @@ -7752,21 +7851,23 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) * @phba: pointer to lpfc hba data structure. * * This routine is called to prepare the SLI3 device for PCI slot recover. It - * aborts and stops all the on-going I/Os on the pci device. + * aborts all the outstanding SCSI I/Os to the pci device. **/ static void lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) { + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2723 PCI channel I/O abort preparing for recovery\n"); - /* Prepare for bringing HBA offline */ - lpfc_offline_prep(phba); - /* Clear sli active flag to prevent sysfs access to HBA */ - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - /* Stop and flush all I/Os and bring HBA offline */ - lpfc_offline(phba); + + /* + * There may be errored I/Os through HBA, abort all I/Os on txcmplq + * and let the SCSI mid-layer to retry them to recover. + */ + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); } /** @@ -7780,21 +7881,24 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) static void lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) { - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2710 PCI channel disable preparing for reset\n"); + + /* Block any management I/Os to the device */ + lpfc_block_mgmt_io(phba); + + /* Block all SCSI devices' I/Os on the host */ + lpfc_scsi_dev_block(phba); + + /* stop all timers */ + lpfc_stop_hba_timers(phba); + /* Disable interrupt and pci device */ lpfc_sli_disable_intr(phba); pci_disable_device(phba->pcidev); - /* - * There may be I/Os dropped by the firmware. - * Error iocb (I/O) on txcmplq and let the SCSI layer - * retry it after re-establishing link. - */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); + + /* Flush all driver's outstanding SCSI I/Os as we are to reset */ + lpfc_sli_flush_fcp_rings(phba); } /** @@ -7806,10 +7910,16 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) * pending I/Os. **/ static void -lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba) +lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2711 PCI channel permanent disable for failure\n"); + /* Block all SCSI devices' I/Os on the host */ + lpfc_scsi_dev_block(phba); + + /* stop all timers */ + lpfc_stop_hba_timers(phba); + /* Clean up all driver's outstanding SCSI I/Os */ lpfc_sli_flush_fcp_rings(phba); } @@ -7838,9 +7948,6 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); - switch (state) { case pci_channel_io_normal: /* Non-fatal error, prepare for recovery */ @@ -7852,7 +7959,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: /* Permanent failure, prepare for device down */ - lpfc_prep_dev_for_perm_failure(phba); + lpfc_sli_prep_dev_for_perm_failure(phba); return PCI_ERS_RESULT_DISCONNECT; default: /* Unknown state, prepare and request slot reset */ @@ -7921,7 +8028,8 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev) } else phba->intr_mode = intr_mode; - /* Take device offline; this will perform cleanup */ + /* Take device offline, it will perform cleanup */ + lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); @@ -7947,7 +8055,7 @@ lpfc_io_resume_s3(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - /* Bring the device online */ + /* Bring device online, it will be no-op for non-fatal error resume */ lpfc_online(phba); /* Clean up Advanced Error Reporting (AER) if needed */ @@ -8052,8 +8160,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) } /* Initialize and populate the iocb list per host */ - error = lpfc_init_iocb_list(phba, - phba->sli4_hba.max_cfg_param.max_xri); + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2821 initialize iocb list %d.\n", + phba->cfg_iocb_cnt*1024); + error = lpfc_init_iocb_list(phba, phba->cfg_iocb_cnt*1024); + if (error) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1413 Failed to initialize iocb list.\n"); @@ -8102,6 +8214,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Default to single FCP EQ for non-MSI-X */ if (phba->intr_type != MSIX) phba->cfg_fcp_eq_count = 1; + else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count) + phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1; /* Set up SLI-4 HBA */ if (lpfc_sli4_hba_setup(phba)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8263,7 +8377,7 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0298 PCI device Power Management suspend.\n"); + "2843 PCI device Power Management suspend.\n"); /* Bring down the device */ lpfc_offline_prep(phba); @@ -8354,6 +8468,84 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) } /** + * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI4 device for PCI slot recover. It + * aborts all the outstanding SCSI I/Os to the pci device. + **/ +static void +lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2828 PCI channel I/O abort preparing for recovery\n"); + /* + * There may be errored I/Os through HBA, abort all I/Os on txcmplq + * and let the SCSI mid-layer to retry them to recover. + */ + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); +} + +/** + * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI4 device for PCI slot reset. It + * disables the device interrupt and pci device, and aborts the internal FCP + * pending I/Os. + **/ +static void +lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2826 PCI channel disable preparing for reset\n"); + + /* Block any management I/Os to the device */ + lpfc_block_mgmt_io(phba); + + /* Block all SCSI devices' I/Os on the host */ + lpfc_scsi_dev_block(phba); + + /* stop all timers */ + lpfc_stop_hba_timers(phba); + + /* Disable interrupt and pci device */ + lpfc_sli4_disable_intr(phba); + pci_disable_device(phba->pcidev); + + /* Flush all driver's outstanding SCSI I/Os as we are to reset */ + lpfc_sli_flush_fcp_rings(phba); +} + +/** + * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI4 device for PCI slot permanently + * disabling. It blocks the SCSI transport layer traffic and flushes the FCP + * pending I/Os. + **/ +static void +lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2827 PCI channel permanent disable for failure\n"); + + /* Block all SCSI devices' I/Os on the host */ + lpfc_scsi_dev_block(phba); + + /* stop all timers */ + lpfc_stop_hba_timers(phba); + + /* Clean up all driver's outstanding SCSI I/Os */ + lpfc_sli_flush_fcp_rings(phba); +} + +/** * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device * @pdev: pointer to PCI device. * @state: the current PCI connection state. @@ -8372,7 +8564,29 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) static pci_ers_result_t lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) { - return PCI_ERS_RESULT_NEED_RESET; + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + switch (state) { + case pci_channel_io_normal: + /* Non-fatal error, prepare for recovery */ + lpfc_sli4_prep_dev_for_recover(phba); + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + /* Fatal error, prepare for slot reset */ + lpfc_sli4_prep_dev_for_reset(phba); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + /* Permanent failure, prepare for device down */ + lpfc_sli4_prep_dev_for_perm_failure(phba); + return PCI_ERS_RESULT_DISCONNECT; + default: + /* Unknown state, prepare and request slot reset */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2825 Unknown PCI error state: x%x\n", state); + lpfc_sli4_prep_dev_for_reset(phba); + return PCI_ERS_RESULT_NEED_RESET; + } } /** @@ -8396,6 +8610,39 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) static pci_ers_result_t lpfc_io_slot_reset_s4(struct pci_dev *pdev) { + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + struct lpfc_sli *psli = &phba->sli; + uint32_t intr_mode; + + dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); + if (pci_enable_device_mem(pdev)) { + printk(KERN_ERR "lpfc: Cannot re-enable " + "PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_restore_state(pdev); + if (pdev->is_busmaster) + pci_set_master(pdev); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI_ACTIVE; + spin_unlock_irq(&phba->hbalock); + + /* Configure and enable interrupt */ + intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); + if (intr_mode == LPFC_INTR_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2824 Cannot re-enable interrupt after " + "slot reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } else + phba->intr_mode = intr_mode; + + /* Log the current active interrupt mode */ + lpfc_log_intr_mode(phba, phba->intr_mode); + return PCI_ERS_RESULT_RECOVERED; } @@ -8412,7 +8659,27 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) static void lpfc_io_resume_s4(struct pci_dev *pdev) { - return; + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + /* + * In case of slot reset, as function reset is performed through + * mailbox command which needs DMA to be enabled, this operation + * has to be moved to the io resume phase. Taking device offline + * will perform the necessary cleanup. + */ + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { + /* Perform device reset */ + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + /* Bring the device back online */ + lpfc_online(phba); + } + + /* Clean up Advanced Error Reporting (AER) if needed */ + if (phba->hba_flag & HBA_AER_ENABLED) + pci_cleanup_aer_uncorrect_error_status(pdev); } /** @@ -8744,6 +9011,8 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS, + PCI_ANY_ID, PCI_ANY_ID, }, { 0 } }; |