lpfc 8.3.25: PCI and SR-IOV Fixes
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / lpfc / lpfc_init.c
index 7dda036a1af38a89e9afff7bbf1804d91c01b3c5..027b797c991630d651e4955846a6af4dcc13cfc5 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ctype.h>
 #include <linux/aer.h>
 #include <linux/slab.h>
+#include <linux/firmware.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -211,7 +212,6 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
        lpfc_vpd_data = kmalloc(DMP_VPD_SIZE, GFP_KERNEL);
        if (!lpfc_vpd_data)
                goto out_free_mbox;
-
        do {
                lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD);
                rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
@@ -308,6 +308,45 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
        return;
 }
 
+/**
+ * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname,
+ *     cfg_soft_wwnn, cfg_soft_wwpn
+ * @vport: pointer to lpfc vport data structure.
+ *
+ *
+ * Return codes
+ *   None.
+ **/
+void
+lpfc_update_vport_wwn(struct lpfc_vport *vport)
+{
+       /* If the soft name exists then update it using the service params */
+       if (vport->phba->cfg_soft_wwnn)
+               u64_to_wwn(vport->phba->cfg_soft_wwnn,
+                          vport->fc_sparam.nodeName.u.wwn);
+       if (vport->phba->cfg_soft_wwpn)
+               u64_to_wwn(vport->phba->cfg_soft_wwpn,
+                          vport->fc_sparam.portName.u.wwn);
+
+       /*
+        * If the name is empty or there exists a soft name
+        * then copy the service params name, otherwise use the fc name
+        */
+       if (vport->fc_nodename.u.wwn[0] == 0 || vport->phba->cfg_soft_wwnn)
+               memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+                       sizeof(struct lpfc_name));
+       else
+               memcpy(&vport->fc_sparam.nodeName, &vport->fc_nodename,
+                       sizeof(struct lpfc_name));
+
+       if (vport->fc_portname.u.wwn[0] == 0 || vport->phba->cfg_soft_wwpn)
+               memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+                       sizeof(struct lpfc_name));
+       else
+               memcpy(&vport->fc_sparam.portName, &vport->fc_portname,
+                       sizeof(struct lpfc_name));
+}
+
 /**
  * lpfc_config_port_post - Perform lpfc initialization after config port
  * @phba: pointer to lpfc hba data structure.
@@ -377,17 +416,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        pmb->context1 = NULL;
-
-       if (phba->cfg_soft_wwnn)
-               u64_to_wwn(phba->cfg_soft_wwnn,
-                          vport->fc_sparam.nodeName.u.wwn);
-       if (phba->cfg_soft_wwpn)
-               u64_to_wwn(phba->cfg_soft_wwpn,
-                          vport->fc_sparam.portName.u.wwn);
-       memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
-              sizeof (struct lpfc_name));
-       memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
-              sizeof (struct lpfc_name));
+       lpfc_update_vport_wwn(vport);
 
        /* Update the fc_host data structures with new wwn. */
        fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
@@ -573,7 +602,6 @@ lpfc_config_port_post(struct lpfc_hba *phba)
                        /* Clear all pending interrupts */
                        writel(0xffffffff, phba->HAregaddr);
                        readl(phba->HAregaddr); /* flush */
-
                        phba->link_state = LPFC_HBA_ERROR;
                        if (rc != MBX_BUSY)
                                mempool_free(pmb, phba->mbox_mem_pool);
@@ -1755,7 +1783,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
                && descp && descp[0] != '\0')
                return;
 
-       if (phba->lmt & LMT_10Gb)
+       if (phba->lmt & LMT_16Gb)
+               max_speed = 16;
+       else if (phba->lmt & LMT_10Gb)
                max_speed = 10;
        else if (phba->lmt & LMT_8Gb)
                max_speed = 8;
@@ -1922,12 +1952,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
                                "Fibre Channel Adapter"};
                break;
        case PCI_DEVICE_ID_LANCER_FC:
-               oneConnect = 1;
-               m = (typeof(m)){"Undefined", "PCIe", "Fibre Channel Adapter"};
+       case PCI_DEVICE_ID_LANCER_FC_VF:
+               m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"};
                break;
        case PCI_DEVICE_ID_LANCER_FCOE:
+       case PCI_DEVICE_ID_LANCER_FCOE_VF:
                oneConnect = 1;
-               m = (typeof(m)){"Undefined", "PCIe", "FCoE"};
+               m = (typeof(m)){"OCe50100", "PCIe", "FCoE"};
                break;
        default:
                m = (typeof(m)){"Unknown", "", ""};
@@ -1936,7 +1967,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
 
        if (mdp && mdp[0] == '\0')
                snprintf(mdp, 79,"%s", m.name);
-       /* oneConnect hba requires special processing, they are all initiators
+       /*
+        * oneConnect hba requires special processing, they are all initiators
         * and we put the port number on the end
         */
        if (descp && descp[0] == '\0') {
@@ -2656,6 +2688,7 @@ lpfc_scsi_free(struct lpfc_hba *phba)
                kfree(io);
                phba->total_iocbq_bufs--;
        }
+
        spin_unlock_irq(&phba->hbalock);
        return 0;
 }
@@ -2894,6 +2927,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
                                 sizeof fc_host_symbolic_name(shost));
 
        fc_host_supported_speeds(shost) = 0;
+       if (phba->lmt & LMT_16Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT;
        if (phba->lmt & LMT_10Gb)
                fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
        if (phba->lmt & LMT_8Gb)
@@ -3612,8 +3647,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
                        "2718 Clear Virtual Link Received for VPI 0x%x"
                        " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
+
                vport = lpfc_find_vport_by_vpid(phba,
-                               acqe_fip->index - phba->vpi_base);
+                                               acqe_fip->index);
                ndlp = lpfc_sli4_perform_vport_cvl(vport);
                if (!ndlp)
                        break;
@@ -3935,6 +3971,10 @@ lpfc_enable_pci_dev(struct lpfc_hba *phba)
        pci_try_set_mwi(pdev);
        pci_save_state(pdev);
 
+       /* PCIe EEH recovery on powerpc platforms needs fundamental reset */
+       if (pci_find_capability(pdev, PCI_CAP_ID_EXP))
+               pdev->needs_freset = 1;
+
        return 0;
 
 out_disable_device:
@@ -3996,6 +4036,73 @@ 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.
+ * @nr_vfn: number of virtual functions to be enabled.
+ *
+ * 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.
+ **/
+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,
+                               "2806 Failed to enable sriov on this device "
+                               "with vfn number nr_vf:%d, rc:%d\n",
+                               nr_vfn, rc);
+       } else
+               lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                               "2807 Successful enable sriov on this device "
+                               "with vfn number nr_vf:%d\n", nr_vfn);
+       return rc;
+}
+
 /**
  * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev.
  * @phba: pointer to lpfc hba data structure.
@@ -4011,6 +4118,7 @@ static int
 lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
 {
        struct lpfc_sli *psli;
+       int rc;
 
        /*
         * Initialize timers used by driver
@@ -4085,6 +4193,23 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
        if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ))
                return -ENOMEM;
 
+       /*
+        * Enable sr-iov virtual functions if supported and configured
+        * through the module parameter.
+        */
+       if (phba->cfg_sriov_nr_virtfn > 0) {
+               rc = lpfc_sli_probe_sriov_nr_virtfn(phba,
+                                                phba->cfg_sriov_nr_virtfn);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                                       "2808 Requested number of SR-IOV "
+                                       "virtual functions (%d) is not "
+                                       "supported\n",
+                                       phba->cfg_sriov_nr_virtfn);
+                       phba->cfg_sriov_nr_virtfn = 0;
+               }
+       }
+
        return 0;
 }
 
@@ -4160,6 +4285,14 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        phba->fcf.redisc_wait.function = lpfc_sli4_fcf_redisc_wait_tmo;
        phba->fcf.redisc_wait.data = (unsigned long)phba;
 
+       /*
+        * Control structure for handling external multi-buffer mailbox
+        * command pass-through.
+        */
+       memset((uint8_t *)&phba->mbox_ext_buf_ctx, 0,
+               sizeof(struct lpfc_mbox_ext_buf_ctx));
+       INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list);
+
        /*
         * We need to do a READ_CONFIG mailbox command here before
         * calling lpfc_get_cfgparam. For VFs this will report the
@@ -4233,7 +4366,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        spin_lock_init(&phba->sli4_hba.abts_sgl_list_lock);
 
        /*
-        * Initialize dirver internal slow-path work queues
+        * Initialize driver internal slow-path work queues
         */
 
        /* Driver internel slow-path CQ Event pool */
@@ -4249,6 +4382,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        /* Receive queue CQ Event work queue list */
        INIT_LIST_HEAD(&phba->sli4_hba.sp_unsol_work_queue);
 
+       /* Initialize extent block lists. */
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_blk_list);
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_xri_blk_list);
+       INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
+       INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
+
        /* Initialize the driver internal SLI layer lists. */
        lpfc_sli_setup(phba);
        lpfc_sli_queue_setup(phba);
@@ -4323,9 +4462,19 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        }
        /*
         * Get sli4 parameters that override parameters from Port capabilities.
-        * If this call fails it is not a critical error so continue loading.
+        * If this call fails, it isn't critical unless the SLI4 parameters come
+        * back in conflict.
         */
-       lpfc_get_sli4_parameters(phba, mboxq);
+       rc = lpfc_get_sli4_parameters(phba, mboxq);
+       if (rc) {
+               if (phba->sli4_hba.extents_in_use &&
+                   phba->sli4_hba.rpi_hdrs_in_use) {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "2999 Unsupported SLI4 Parameters "
+                               "Extents and RPI headers enabled.\n");
+                       goto out_free_bsmbx;
+               }
+       }
        mempool_free(mboxq, phba->mbox_mem_pool);
        /* Create all the SLI4 queues */
        rc = lpfc_sli4_queue_create(phba);
@@ -4350,7 +4499,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                                "1430 Failed to initialize sgl list.\n");
                goto out_free_sgl_list;
        }
-
        rc = lpfc_sli4_init_rpi_hdrs(phba);
        if (rc) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -4366,6 +4514,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2759 Failed allocate memory for FCF round "
                                "robin failover bmask\n");
+               rc = -ENOMEM;
                goto out_remove_rpi_hdrs;
        }
 
@@ -4375,6 +4524,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2572 Failed allocate memory for fast-path "
                                "per-EQ handle array\n");
+               rc = -ENOMEM;
                goto out_free_fcf_rr_bmask;
        }
 
@@ -4384,10 +4534,28 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2573 Failed allocate memory for msi-x "
                                "interrupt vector entries\n");
+               rc = -ENOMEM;
                goto out_free_fcp_eq_hdl;
        }
 
-       return rc;
+       /*
+        * Enable sr-iov virtual functions if supported and configured
+        * through the module parameter.
+        */
+       if (phba->cfg_sriov_nr_virtfn > 0) {
+               rc = lpfc_sli_probe_sriov_nr_virtfn(phba,
+                                                phba->cfg_sriov_nr_virtfn);
+               if (rc) {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+                                       "3020 Requested number of SR-IOV "
+                                       "virtual functions (%d) is not "
+                                       "supported\n",
+                                       phba->cfg_sriov_nr_virtfn);
+                       phba->cfg_sriov_nr_virtfn = 0;
+               }
+       }
+
+       return 0;
 
 out_free_fcp_eq_hdl:
        kfree(phba->sli4_hba.fcp_eq_hdl);
@@ -4449,6 +4617,9 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
        lpfc_sli4_cq_event_release_all(phba);
        lpfc_sli4_cq_event_pool_destroy(phba);
 
+       /* Release resource identifiers. */
+       lpfc_sli4_dealloc_resource_identifiers(phba);
+
        /* Free the bsmbx region. */
        lpfc_destroy_bootstrap_mbox(phba);
 
@@ -4649,6 +4820,7 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count)
                                "Unloading driver.\n", __func__);
                        goto out_free_iocbq;
                }
+               iocbq_entry->sli4_lxritag = NO_XRI;
                iocbq_entry->sli4_xritag = NO_XRI;
 
                spin_lock_irq(&phba->hbalock);
@@ -4746,7 +4918,7 @@ lpfc_init_sgl_list(struct lpfc_hba *phba)
 
        els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba);
        lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                               "2400 lpfc_init_sgl_list els %d.\n",
+                               "2400 ELS XRI count %d.\n",
                                els_xri_cnt);
        /* Initialize and populate the sglq list per host/VF. */
        INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list);
@@ -4779,7 +4951,6 @@ lpfc_init_sgl_list(struct lpfc_hba *phba)
        phba->sli4_hba.scsi_xri_max =
                        phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt;
        phba->sli4_hba.scsi_xri_cnt = 0;
-
        phba->sli4_hba.lpfc_scsi_psb_array =
                        kzalloc((sizeof(struct lpfc_scsi_buf *) *
                        phba->sli4_hba.scsi_xri_max), GFP_KERNEL);
@@ -4802,13 +4973,6 @@ lpfc_init_sgl_list(struct lpfc_hba *phba)
                        goto out_free_mem;
                }
 
-               sglq_entry->sli4_xritag = lpfc_sli4_next_xritag(phba);
-               if (sglq_entry->sli4_xritag == NO_XRI) {
-                       kfree(sglq_entry);
-                       printk(KERN_ERR "%s: failed to allocate XRI.\n"
-                               "Unloading driver.\n", __func__);
-                       goto out_free_mem;
-               }
                sglq_entry->buff_type = GEN_BUFF_TYPE;
                sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys);
                if (sglq_entry->virt == NULL) {
@@ -4841,40 +5005,33 @@ out_free_mem:
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to post rpi header templates to the
- * HBA consistent with the SLI-4 interface spec.  This routine
+ * port for those SLI4 ports that do not support extents.  This routine
  * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
- * No locks are held here because this is an initialization routine
- * called only from probe or lpfc_online when interrupts are not
- * enabled and the driver is reinitializing the device.
+ * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine
+ * and should be called only when interrupts are disabled.
  *
  * Return codes
  *     0 - successful
- *     -ENOMEM - No available memory
- *      -EIO - The mailbox failed to complete successfully.
+ *     -ERROR - otherwise.
  **/
 int
 lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba)
 {
        int rc = 0;
-       int longs;
-       uint16_t rpi_count;
        struct lpfc_rpi_hdr *rpi_hdr;
 
        INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list);
-
        /*
-        * Provision an rpi bitmask range for discovery. The total count
-        * is the difference between max and base + 1.
+        * If the SLI4 port supports extents, posting the rpi header isn't
+        * required.  Set the expected maximum count and let the actual value
+        * get set when extents are fully allocated.
         */
-       rpi_count = phba->sli4_hba.max_cfg_param.rpi_base +
-                   phba->sli4_hba.max_cfg_param.max_rpi - 1;
-
-       longs = ((rpi_count) + BITS_PER_LONG - 1) / BITS_PER_LONG;
-       phba->sli4_hba.rpi_bmask = kzalloc(longs * sizeof(unsigned long),
-                                          GFP_KERNEL);
-       if (!phba->sli4_hba.rpi_bmask)
-               return -ENOMEM;
+       if (!phba->sli4_hba.rpi_hdrs_in_use) {
+               phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi;
+               return rc;
+       }
+       if (phba->sli4_hba.extents_in_use)
+               return -EIO;
 
        rpi_hdr = lpfc_sli4_create_rpi_hdr(phba);
        if (!rpi_hdr) {
@@ -4908,11 +5065,28 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
        struct lpfc_rpi_hdr *rpi_hdr;
        uint32_t rpi_count;
 
+       /*
+        * If the SLI4 port supports extents, posting the rpi header isn't
+        * required.  Set the expected maximum count and let the actual value
+        * get set when extents are fully allocated.
+        */
+       if (!phba->sli4_hba.rpi_hdrs_in_use)
+               return NULL;
+       if (phba->sli4_hba.extents_in_use)
+               return NULL;
+
+       /* The limit on the logical index is just the max_rpi count. */
        rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base +
-                   phba->sli4_hba.max_cfg_param.max_rpi - 1;
+       phba->sli4_hba.max_cfg_param.max_rpi - 1;
 
        spin_lock_irq(&phba->hbalock);
-       curr_rpi_range = phba->sli4_hba.next_rpi;
+       /*
+        * Establish the starting RPI in this header block.  The starting
+        * rpi is normalized to a zero base because the physical rpi is
+        * port based.
+        */
+       curr_rpi_range = phba->sli4_hba.next_rpi -
+               phba->sli4_hba.max_cfg_param.rpi_base;
        spin_unlock_irq(&phba->hbalock);
 
        /*
@@ -4925,6 +5099,8 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
        else
                rpi_count = LPFC_RPI_HDR_COUNT;
 
+       if (!rpi_count)
+               return NULL;
        /*
         * First allocate the protocol header region for the port.  The
         * port expects a 4KB DMA-mapped memory region that is 4K aligned.
@@ -4957,12 +5133,14 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
        rpi_hdr->len = LPFC_HDR_TEMPLATE_SIZE;
        rpi_hdr->page_count = 1;
        spin_lock_irq(&phba->hbalock);
-       rpi_hdr->start_rpi = phba->sli4_hba.next_rpi;
+
+       /* The rpi_hdr stores the logical index only. */
+       rpi_hdr->start_rpi = curr_rpi_range;
        list_add_tail(&rpi_hdr->list, &phba->sli4_hba.lpfc_rpi_hdr_list);
 
        /*
-        * The next_rpi stores the next module-64 rpi value to post
-        * in any subsequent rpi memory region postings.
+        * The next_rpi stores the next logical module-64 rpi value used
+        * to post physical rpis in subsequent rpi postings.
         */
        phba->sli4_hba.next_rpi += rpi_count;
        spin_unlock_irq(&phba->hbalock);
@@ -4981,15 +5159,18 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to remove all memory resources allocated
- * to support rpis. This routine presumes the caller has released all
- * rpis consumed by fabric or port logins and is prepared to have
- * the header pages removed.
+ * to support rpis for SLI4 ports not supporting extents. This routine
+ * presumes the caller has released all rpis consumed by fabric or port
+ * logins and is prepared to have the header pages removed.
  **/
 void
 lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba)
 {
        struct lpfc_rpi_hdr *rpi_hdr, *next_rpi_hdr;
 
+       if (!phba->sli4_hba.rpi_hdrs_in_use)
+               goto exit;
+
        list_for_each_entry_safe(rpi_hdr, next_rpi_hdr,
                                 &phba->sli4_hba.lpfc_rpi_hdr_list, list) {
                list_del(&rpi_hdr->list);
@@ -4998,9 +5179,9 @@ lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba)
                kfree(rpi_hdr->dmabuf);
                kfree(rpi_hdr);
        }
-
-       phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
-       memset(phba->sli4_hba.rpi_bmask, 0, sizeof(*phba->sli4_hba.rpi_bmask));
+ exit:
+       /* There are no rpis available to the port now. */
+       phba->sli4_hba.next_rpi = 0;
 }
 
 /**
@@ -5487,7 +5668,8 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
                        /* Final checks.  The port status should be clean. */
                        if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
                                &reg_data.word0) ||
-                               bf_get(lpfc_sliport_status_err, &reg_data)) {
+                               (bf_get(lpfc_sliport_status_err, &reg_data) &&
+                                !bf_get(lpfc_sliport_status_rn, &reg_data))) {
                                phba->work_status[0] =
                                        readl(phba->sli4_hba.u.if_type2.
                                              ERR1regaddr);
@@ -5541,17 +5723,22 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
                break;
        case LPFC_SLI_INTF_IF_TYPE_2:
                phba->sli4_hba.u.if_type2.ERR1regaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_ER1_OFFSET;
                phba->sli4_hba.u.if_type2.ERR2regaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_ER2_OFFSET;
                phba->sli4_hba.u.if_type2.CTRLregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_CTL_OFFSET;
                phba->sli4_hba.u.if_type2.STATUSregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_STA_OFFSET;
                phba->sli4_hba.SLIINTFregaddr =
                        phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
                phba->sli4_hba.PSMPHRregaddr =
-                    phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_SEM_OFFSET;
                phba->sli4_hba.RQDBregaddr =
                        phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;
                phba->sli4_hba.WQDBregaddr =
@@ -5741,7 +5928,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
 {
        LPFC_MBOXQ_t *pmb;
        struct lpfc_mbx_read_config *rd_config;
-       uint32_t rc = 0;
+       union  lpfc_sli4_cfg_shdr *shdr;
+       uint32_t shdr_status, shdr_add_status;
+       struct lpfc_mbx_get_func_cfg *get_func_cfg;
+       struct lpfc_rsrc_desc_fcfcoe *desc;
+       uint32_t desc_count;
+       int length, i, rc = 0;
 
        pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmb) {
@@ -5763,6 +5955,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                rc = -EIO;
        } else {
                rd_config = &pmb->u.mqe.un.rd_config;
+               phba->sli4_hba.extents_in_use =
+                       bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config);
                phba->sli4_hba.max_cfg_param.max_xri =
                        bf_get(lpfc_mbx_rd_conf_xri_count, rd_config);
                phba->sli4_hba.max_cfg_param.xri_base =
@@ -5781,8 +5975,6 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                        bf_get(lpfc_mbx_rd_conf_vfi_base, rd_config);
                phba->sli4_hba.max_cfg_param.max_fcfi =
                        bf_get(lpfc_mbx_rd_conf_fcfi_count, rd_config);
-               phba->sli4_hba.max_cfg_param.fcfi_base =
-                       bf_get(lpfc_mbx_rd_conf_fcfi_base, rd_config);
                phba->sli4_hba.max_cfg_param.max_eq =
                        bf_get(lpfc_mbx_rd_conf_eq_count, rd_config);
                phba->sli4_hba.max_cfg_param.max_rq =
@@ -5800,11 +5992,13 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                                (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0;
                phba->max_vports = phba->max_vpi;
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                               "2003 cfg params XRI(B:%d M:%d), "
+                               "2003 cfg params Extents? %d "
+                               "XRI(B:%d M:%d), "
                                "VPI(B:%d M:%d) "
                                "VFI(B:%d M:%d) "
                                "RPI(B:%d M:%d) "
-                               "FCFI(B:%d M:%d)\n",
+                               "FCFI(Count:%d)\n",
+                               phba->sli4_hba.extents_in_use,
                                phba->sli4_hba.max_cfg_param.xri_base,
                                phba->sli4_hba.max_cfg_param.max_xri,
                                phba->sli4_hba.max_cfg_param.vpi_base,
@@ -5813,10 +6007,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                                phba->sli4_hba.max_cfg_param.max_vfi,
                                phba->sli4_hba.max_cfg_param.rpi_base,
                                phba->sli4_hba.max_cfg_param.max_rpi,
-                               phba->sli4_hba.max_cfg_param.fcfi_base,
                                phba->sli4_hba.max_cfg_param.max_fcfi);
        }
-       mempool_free(pmb, phba->mbox_mem_pool);
+
+       if (rc)
+               goto read_cfg_out;
 
        /* Reset the DFT_HBA_Q_DEPTH to the max xri  */
        if (phba->cfg_hba_queue_depth >
@@ -5825,6 +6020,65 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
                phba->cfg_hba_queue_depth =
                        phba->sli4_hba.max_cfg_param.max_xri -
                                lpfc_sli4_get_els_iocb_cnt(phba);
+
+       if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+           LPFC_SLI_INTF_IF_TYPE_2)
+               goto read_cfg_out;
+
+       /* get the pf# and vf# for SLI4 if_type 2 port */
+       length = (sizeof(struct lpfc_mbx_get_func_cfg) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, pmb, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG,
+                        length, LPFC_SLI4_MBX_EMBED);
+
+       rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
+       shdr = (union lpfc_sli4_cfg_shdr *)
+                               &pmb->u.mqe.un.sli4_config.header.cfg_shdr;
+       shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
+       shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
+       if (rc || shdr_status || shdr_add_status) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "3026 Mailbox failed , mbxCmd x%x "
+                               "GET_FUNCTION_CONFIG, mbxStatus x%x\n",
+                               bf_get(lpfc_mqe_command, &pmb->u.mqe),
+                               bf_get(lpfc_mqe_status, &pmb->u.mqe));
+               rc = -EIO;
+               goto read_cfg_out;
+       }
+
+       /* search for fc_fcoe resrouce descriptor */
+       get_func_cfg = &pmb->u.mqe.un.get_func_cfg;
+       desc_count = get_func_cfg->func_cfg.rsrc_desc_count;
+
+       for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
+               desc = (struct lpfc_rsrc_desc_fcfcoe *)
+                       &get_func_cfg->func_cfg.desc[i];
+               if (LPFC_RSRC_DESC_TYPE_FCFCOE ==
+                   bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
+                       phba->sli4_hba.iov.pf_number =
+                               bf_get(lpfc_rsrc_desc_fcfcoe_pfnum, desc);
+                       phba->sli4_hba.iov.vf_number =
+                               bf_get(lpfc_rsrc_desc_fcfcoe_vfnum, desc);
+                       break;
+               }
+       }
+
+       if (i < LPFC_RSRC_DESC_MAX_NUM)
+               lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                               "3027 GET_FUNCTION_CONFIG: pf_number:%d, "
+                               "vf_number:%d\n", phba->sli4_hba.iov.pf_number,
+                               phba->sli4_hba.iov.vf_number);
+       else {
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "3028 GET_FUNCTION_CONFIG: failed to find "
+                               "Resrouce Descriptor:x%x\n",
+                               LPFC_RSRC_DESC_TYPE_FCFCOE);
+               rc = -EIO;
+       }
+
+read_cfg_out:
+       mempool_free(pmb, phba->mbox_mem_pool);
        return rc;
 }
 
@@ -6229,8 +6483,10 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
        phba->sli4_hba.mbx_cq = NULL;
 
        /* Release FCP response complete queue */
-       for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++)
+       fcp_qidx = 0;
+       do
                lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]);
+       while (++fcp_qidx < phba->cfg_fcp_eq_count);
        kfree(phba->sli4_hba.fcp_cq);
        phba->sli4_hba.fcp_cq = NULL;
 
@@ -6353,16 +6609,24 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
                        phba->sli4_hba.sp_eq->queue_id);
 
        /* Set up fast-path FCP Response Complete Queue */
-       for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) {
+       fcp_cqidx = 0;
+       do {
                if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "0526 Fast-path FCP CQ (%d) not "
                                        "allocated\n", fcp_cqidx);
                        goto out_destroy_fcp_cq;
                }
-               rc = lpfc_cq_create(phba, phba->sli4_hba.fcp_cq[fcp_cqidx],
-                                   phba->sli4_hba.fp_eq[fcp_cqidx],
-                                   LPFC_WCQ, LPFC_FCP);
+               if (phba->cfg_fcp_eq_count)
+                       rc = lpfc_cq_create(phba,
+                                           phba->sli4_hba.fcp_cq[fcp_cqidx],
+                                           phba->sli4_hba.fp_eq[fcp_cqidx],
+                                           LPFC_WCQ, LPFC_FCP);
+               else
+                       rc = lpfc_cq_create(phba,
+                                           phba->sli4_hba.fcp_cq[fcp_cqidx],
+                                           phba->sli4_hba.sp_eq,
+                                           LPFC_WCQ, LPFC_FCP);
                if (rc) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "0527 Failed setup of fast-path FCP "
@@ -6371,12 +6635,15 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
                }
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                                "2588 FCP CQ setup: cq[%d]-id=%d, "
-                               "parent eq[%d]-id=%d\n",
+                               "parent %seq[%d]-id=%d\n",
                                fcp_cqidx,
                                phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id,
+                               (phba->cfg_fcp_eq_count) ? "" : "sp_",
                                fcp_cqidx,
-                               phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id);
-       }
+                               (phba->cfg_fcp_eq_count) ?
+                                  phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id :
+                                  phba->sli4_hba.sp_eq->queue_id);
+       } while (++fcp_cqidx < phba->cfg_fcp_eq_count);
 
        /*
         * Set up all the Work Queues (WQs)
@@ -6445,7 +6712,9 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
                                fcp_cq_index,
                                phba->sli4_hba.fcp_cq[fcp_cq_index]->queue_id);
                /* Round robin FCP Work Queue's Completion Queue assignment */
-               fcp_cq_index = ((fcp_cq_index + 1) % phba->cfg_fcp_eq_count);
+               if (phba->cfg_fcp_eq_count)
+                       fcp_cq_index = ((fcp_cq_index + 1) %
+                                       phba->cfg_fcp_eq_count);
        }
 
        /*
@@ -6827,6 +7096,8 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
                        if (rdy_chk < 1000)
                                break;
                }
+               /* delay driver action following IF_TYPE_2 function reset */
+               msleep(100);
                break;
        case LPFC_SLI_INTF_IF_TYPE_1:
        default:
@@ -7419,11 +7690,15 @@ enable_msix_vectors:
        /*
         * Assign MSI-X vectors to interrupt handlers
         */
-
-       /* The first vector must associated to slow-path handler for MQ */
-       rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
-                        &lpfc_sli4_sp_intr_handler, IRQF_SHARED,
-                        LPFC_SP_DRIVER_HANDLER_NAME, phba);
+       if (vectors > 1)
+               rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
+                                &lpfc_sli4_sp_intr_handler, IRQF_SHARED,
+                                LPFC_SP_DRIVER_HANDLER_NAME, phba);
+       else
+               /* All Interrupts need to be handled by one EQ */
+               rc = request_irq(phba->sli4_hba.msix_entries[0].vector,
+                                &lpfc_sli4_intr_handler, IRQF_SHARED,
+                                LPFC_DRIVER_NAME, phba);
        if (rc) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
                                "0485 MSI-X slow-path request_irq failed "
@@ -7765,6 +8040,7 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
 {
        int wait_cnt = 0;
        LPFC_MBOXQ_t *mboxq;
+       struct pci_dev *pdev = phba->pcidev;
 
        lpfc_stop_hba_timers(phba);
        phba->sli4_hba.intr_enable = 0;
@@ -7804,6 +8080,10 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
        /* Disable PCI subsystem interrupt */
        lpfc_sli4_disable_intr(phba);
 
+       /* Disable SR-IOV if enabled */
+       if (phba->cfg_sriov_nr_virtfn)
+               pci_disable_sriov(pdev);
+
        /* Stop kthread signal shall trigger work_done one more time */
        kthread_stop(phba->worker_thread);
 
@@ -7878,6 +8158,11 @@ lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        sli4_params->hdr_pp_align = bf_get(hdr_pp_align, &mqe->un.sli4_params);
        sli4_params->sgl_pages_max = bf_get(sgl_pages, &mqe->un.sli4_params);
        sli4_params->sgl_pp_align = bf_get(sgl_pp_align, &mqe->un.sli4_params);
+
+       /* Make sure that sge_supp_len can be handled by the driver */
+       if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE)
+               sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
+
        return rc;
 }
 
@@ -7902,6 +8187,13 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        int length;
        struct lpfc_sli4_parameters *mbx_sli4_parameters;
 
+       /*
+        * By default, the driver assumes the SLI4 port requires RPI
+        * header postings.  The SLI4_PARAM response will correct this
+        * assumption.
+        */
+       phba->sli4_hba.rpi_hdrs_in_use = 1;
+
        /* Read the port's SLI4 Config Parameters */
        length = (sizeof(struct lpfc_mbx_get_sli4_parameters) -
                  sizeof(struct lpfc_sli4_cfg_mhdr));
@@ -7938,6 +8230,13 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                                            mbx_sli4_parameters);
        sli4_params->sgl_pp_align = bf_get(cfg_sgl_pp_align,
                                           mbx_sli4_parameters);
+       phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters);
+       phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters);
+
+       /* Make sure that sge_supp_len can be handled by the driver */
+       if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE)
+               sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
+
        return 0;
 }
 
@@ -8173,6 +8472,10 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
 
        lpfc_debugfs_terminate(vport);
 
+       /* Disable SR-IOV if enabled */
+       if (phba->cfg_sriov_nr_virtfn)
+               pci_disable_sriov(pdev);
+
        /* Disable interrupt */
        lpfc_sli_disable_intr(phba);
 
@@ -8564,6 +8867,97 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
                return 0;
 }
 
+/**
+ * lpfc_write_firmware - attempt to write a firmware image to the port
+ * @phba: pointer to lpfc hba data structure.
+ * @fw: pointer to firmware image returned from request_firmware.
+ *
+ * returns the number of bytes written if write is successful.
+ * returns a negative error value if there were errors.
+ * returns 0 if firmware matches currently active firmware on port.
+ **/
+int
+lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
+{
+       char fwrev[32];
+       struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data;
+       struct list_head dma_buffer_list;
+       int i, rc = 0;
+       struct lpfc_dmabuf *dmabuf, *next;
+       uint32_t offset = 0, temp_offset = 0;
+
+       INIT_LIST_HEAD(&dma_buffer_list);
+       if ((image->magic_number != LPFC_GROUP_OJECT_MAGIC_NUM) ||
+           (bf_get(lpfc_grp_hdr_file_type, image) != LPFC_FILE_TYPE_GROUP) ||
+           (bf_get(lpfc_grp_hdr_id, image) != LPFC_FILE_ID_GROUP) ||
+           (image->size != fw->size)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3022 Invalid FW image found. "
+                               "Magic:%d Type:%x ID:%x\n",
+                               image->magic_number,
+                               bf_get(lpfc_grp_hdr_file_type, image),
+                               bf_get(lpfc_grp_hdr_id, image));
+               return -EINVAL;
+       }
+       lpfc_decode_firmware_rev(phba, fwrev, 1);
+       if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3023 Updating Firmware. Current Version:%s "
+                               "New Version:%s\n",
+                               fwrev, image->revision);
+               for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
+                       dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
+                                        GFP_KERNEL);
+                       if (!dmabuf) {
+                               rc = -ENOMEM;
+                               goto out;
+                       }
+                       dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
+                                                         SLI4_PAGE_SIZE,
+                                                         &dmabuf->phys,
+                                                         GFP_KERNEL);
+                       if (!dmabuf->virt) {
+                               kfree(dmabuf);
+                               rc = -ENOMEM;
+                               goto out;
+                       }
+                       list_add_tail(&dmabuf->list, &dma_buffer_list);
+               }
+               while (offset < fw->size) {
+                       temp_offset = offset;
+                       list_for_each_entry(dmabuf, &dma_buffer_list, list) {
+                               if (offset + SLI4_PAGE_SIZE > fw->size) {
+                                       temp_offset += fw->size - offset;
+                                       memcpy(dmabuf->virt,
+                                              fw->data + temp_offset,
+                                              fw->size - offset);
+                                       break;
+                               }
+                               memcpy(dmabuf->virt, fw->data + temp_offset,
+                                      SLI4_PAGE_SIZE);
+                               temp_offset += SLI4_PAGE_SIZE;
+                       }
+                       rc = lpfc_wr_object(phba, &dma_buffer_list,
+                                   (fw->size - offset), &offset);
+                       if (rc) {
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "3024 Firmware update failed. "
+                                               "%d\n", rc);
+                               goto out;
+                       }
+               }
+               rc = offset;
+       }
+out:
+       list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
+               list_del(&dmabuf->list);
+               dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
+                                 dmabuf->virt, dmabuf->phys);
+               kfree(dmabuf);
+       }
+       return rc;
+}
+
 /**
  * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys
  * @pdev: pointer to PCI device
@@ -8591,6 +8985,10 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        int error;
        uint32_t cfg_mode, intr_mode;
        int mcnt;
+       int adjusted_fcp_eq_count;
+       int fcp_qidx;
+       const struct firmware *fw;
+       uint8_t file_name[16];
 
        /* Allocate memory for HBA structure */
        phba = lpfc_hba_alloc(pdev);
@@ -8688,11 +9086,25 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
                        error = -ENODEV;
                        goto out_free_sysfs_attr;
                }
-               /* Default to single FCP EQ for non-MSI-X */
+               /* Default to single 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;
+                       adjusted_fcp_eq_count = 0;
+               else if (phba->sli4_hba.msix_vec_nr <
+                                       phba->cfg_fcp_eq_count + 1)
+                       adjusted_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1;
+               else
+                       adjusted_fcp_eq_count = phba->cfg_fcp_eq_count;
+               /* Free unused EQs */
+               for (fcp_qidx = adjusted_fcp_eq_count;
+                    fcp_qidx < phba->cfg_fcp_eq_count;
+                    fcp_qidx++) {
+                       lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]);
+                       /* do not delete the first fcp_cq */
+                       if (fcp_qidx)
+                               lpfc_sli4_queue_free(
+                                       phba->sli4_hba.fcp_cq[fcp_qidx]);
+               }
+               phba->cfg_fcp_eq_count = adjusted_fcp_eq_count;
                /* Set up SLI-4 HBA */
                if (lpfc_sli4_hba_setup(phba)) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -8731,6 +9143,14 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        /* Perform post initialization setup */
        lpfc_post_init_setup(phba);
 
+       /* check for firmware upgrade or downgrade */
+       snprintf(file_name, 16, "%s.grp", phba->ModelName);
+       error = request_firmware(&fw, file_name, &phba->pcidev->dev);
+       if (!error) {
+               lpfc_write_firmware(phba, fw);
+               release_firmware(fw);
+       }
+
        /* Check if there are static vports to be created. */
        lpfc_create_static_vport(phba);
 
@@ -9104,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);
 
@@ -9498,6 +9925,10 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };