From c02aabcf67bd5d770602eeb6a5cada6f482de696 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 22 Jul 2011 18:37:28 -0400 Subject: lpfc 8.3.25: PCI and SR-IOV Fixes commit 0a96e9754d6c4a2a31e50ee6c6e36ec13f80bc25 upstream. PCI and SR-IOV Fixes - Call pci_save_state after the pci_restore_state completes. - After calling pci_enable_pcie_error_reporting() and checking the return value for logging messages from rc, reset rc to 0 to it will not later be interpreted for error. - Read PCI config space SR-IOV capability to get the number of VFs supported. - Check for the PF's supported number of VFs before invoking PCI enable sriov API call and log error message that user requested number of VFs is beyond the PF capability if such request is passed in. - Added check for Physical function with Virtual Functions attached. If so, first disable all the VFs before proceeding to device reset. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_attr.c | 76 ++----------------------------------------- drivers/scsi/lpfc/lpfc_crtn.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 44 +++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_sli.c | 1 + 4 files changed, 49 insertions(+), 73 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index bffd86f204d..80ca11c5158 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1466,80 +1466,10 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct pci_dev *pdev = phba->pcidev; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t shdr_status, shdr_add_status; - LPFC_MBOXQ_t *mboxq; - struct lpfc_mbx_get_prof_cfg *get_prof_cfg; - struct lpfc_rsrc_desc_pcie *desc; - uint32_t max_nr_virtfn; - uint32_t desc_count; - int length, rc, i; - - if ((phba->sli_rev < LPFC_SLI_REV4) || - (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2)) - return -EPERM; - - if (!pdev->is_physfn) - return snprintf(buf, PAGE_SIZE, "%d\n", 0); - - mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) - return -ENOMEM; - - /* get the maximum number of virtfn support by physfn */ - length = (sizeof(struct lpfc_mbx_get_prof_cfg) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG, - length, LPFC_SLI4_MBX_EMBED); - shdr = (union lpfc_sli4_cfg_shdr *) - &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; - bf_set(lpfc_mbox_hdr_pf_num, &shdr->request, - phba->sli4_hba.iov.pf_number + 1); - - get_prof_cfg = &mboxq->u.mqe.un.get_prof_cfg; - bf_set(lpfc_mbx_get_prof_cfg_prof_tp, &get_prof_cfg->u.request, - LPFC_CFG_TYPE_CURRENT_ACTIVE); - - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, - lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG)); - - if (rc != MBX_TIMEOUT) { - /* check return status */ - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (shdr_status || shdr_add_status || rc) - goto error_out; - - } else - goto error_out; - - desc_count = get_prof_cfg->u.response.prof_cfg.rsrc_desc_count; - - for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) { - desc = (struct lpfc_rsrc_desc_pcie *) - &get_prof_cfg->u.response.prof_cfg.desc[i]; - if (LPFC_RSRC_DESC_TYPE_PCIE == - bf_get(lpfc_rsrc_desc_pcie_type, desc)) { - max_nr_virtfn = bf_get(lpfc_rsrc_desc_pcie_nr_virtfn, - desc); - break; - } - } - - if (i < LPFC_RSRC_DESC_MAX_NUM) { - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); - return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); - } + uint16_t max_nr_virtfn; -error_out: - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); - return -EIO; + max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba); + return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); } /** diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index a4f00cc72f4..1e41af8dea7 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -440,3 +440,4 @@ struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t, int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *); /* functions to support SR-IOV */ int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); +uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 9d3e8affccb..027b797c991 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4036,6 +4036,34 @@ lpfc_reset_hba(struct lpfc_hba *phba) lpfc_unblock_mgmt_io(phba); } +/** + * lpfc_sli_sriov_nr_virtfn_get - Get the number of sr-iov virtual functions + * @phba: pointer to lpfc hba data structure. + * + * This function enables the PCI SR-IOV virtual functions to a physical + * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to + * enable the number of virtual functions to the physical function. As + * not all devices support SR-IOV, the return code from the pci_enable_sriov() + * API call does not considered as an error condition for most of the device. + **/ +uint16_t +lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba) +{ + struct pci_dev *pdev = phba->pcidev; + uint16_t nr_virtfn; + int pos; + + if (!pdev->is_physfn) + return 0; + + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); + if (pos == 0) + return 0; + + pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF, &nr_virtfn); + return nr_virtfn; +} + /** * lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions * @phba: pointer to lpfc hba data structure. @@ -4051,8 +4079,17 @@ int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn) { struct pci_dev *pdev = phba->pcidev; + uint16_t max_nr_vfn; int rc; + max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba); + if (nr_vfn > max_nr_vfn) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3057 Requested vfs (%d) greater than " + "supported vfs (%d)", nr_vfn, max_nr_vfn); + return -EINVAL; + } + rc = pci_enable_sriov(pdev, nr_vfn); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -9487,6 +9524,13 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) } pci_restore_state(pdev); + + /* + * As the new kernel behavior of pci_restore_state() API call clears + * device saved_state flag, need to save the restored state again. + */ + pci_save_state(pdev); + if (pdev->is_busmaster) pci_set_master(pdev); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 59d81624a85..5b28ea1d72c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5839,6 +5839,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "Advanced Error Reporting (AER)\n"); phba->cfg_aer_support = 0; } + rc = 0; } if (!(phba->hba_flag & HBA_FCOE_MODE)) { -- cgit v1.2.3-18-g5258