[SCSI] lpfc 8.3.25: PCI and SR-IOV Fixes
James Smart [Fri, 22 Jul 2011 22:37:28 +0000 (18:37 -0400)]
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 <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli.c

index bffd86f..80ca11c 100644 (file)
@@ -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);
 }
 
 /**
index a4f00cc..1e41af8 100644 (file)
@@ -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 *);
index 9d3e8af..027b797 100644 (file)
@@ -4037,6 +4037,34 @@ lpfc_reset_hba(struct lpfc_hba *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.
  * @nr_vfn: number of virtual functions to be enabled.
@@ -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);
 
index 59d8162..5b28ea1 100644 (file)
@@ -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)) {