]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/qla2xxx/qla_init.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-omap-h63xx.git] / drivers / scsi / qla2xxx / qla_init.c
index 2a45aec4ff29e6499a36456d24f6f496caf9ff4a..374abe19b5474f3ff18115604c76d230522f6e46 100644 (file)
@@ -79,20 +79,20 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
        set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
 
        qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
-       rval = ha->isp_ops.pci_config(ha);
+       rval = ha->isp_ops->pci_config(ha);
        if (rval) {
                DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
                    ha->host_no));
                return (rval);
        }
 
-       ha->isp_ops.reset_chip(ha);
+       ha->isp_ops->reset_chip(ha);
 
-       ha->isp_ops.get_flash_version(ha, ha->request_ring);
+       ha->isp_ops->get_flash_version(ha, ha->request_ring);
 
        qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
 
-       ha->isp_ops.nvram_config(ha);
+       ha->isp_ops->nvram_config(ha);
 
        if (ha->flags.disable_serdes) {
                /* Mask HBA via NVRAM settings? */
@@ -108,7 +108,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
        qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
 
        if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
-               rval = ha->isp_ops.chip_diag(ha);
+               rval = ha->isp_ops->chip_diag(ha);
                if (rval)
                        return (rval);
                rval = qla2x00_setup_chip(ha);
@@ -129,14 +129,13 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 int
 qla2100_pci_config(scsi_qla_host_t *ha)
 {
-       int ret;
        uint16_t w;
        uint32_t d;
        unsigned long flags;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        pci_set_master(ha->pdev);
-       ret = pci_set_mwi(ha->pdev);
+       pci_try_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
        w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -164,7 +163,6 @@ qla2100_pci_config(scsi_qla_host_t *ha)
 int
 qla2300_pci_config(scsi_qla_host_t *ha)
 {
-       int             ret;
        uint16_t        w;
        uint32_t        d;
        unsigned long   flags = 0;
@@ -172,7 +170,7 @@ qla2300_pci_config(scsi_qla_host_t *ha)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        pci_set_master(ha->pdev);
-       ret = pci_set_mwi(ha->pdev);
+       pci_try_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
        w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -250,15 +248,13 @@ qla2300_pci_config(scsi_qla_host_t *ha)
 int
 qla24xx_pci_config(scsi_qla_host_t *ha)
 {
-       int ret;
        uint16_t w;
        uint32_t d;
        unsigned long flags = 0;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-       int pcix_cmd_reg, pcie_dctl_reg;
 
        pci_set_master(ha->pdev);
-       ret = pci_set_mwi(ha->pdev);
+       pci_try_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
        w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -268,35 +264,19 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
        pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
 
        /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
-       pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
-       if (pcix_cmd_reg) {
-               uint16_t pcix_cmd;
-
-               pcix_cmd_reg += PCI_X_CMD;
-               pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
-               pcix_cmd &= ~PCI_X_CMD_MAX_READ;
-               pcix_cmd |= 0x0008;
-               pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
-       }
+       if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
+               pcix_set_mmrbc(ha->pdev, 2048);
 
        /* PCIe -- adjust Maximum Read Request Size (2048). */
-       pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
-       if (pcie_dctl_reg) {
-               uint16_t pcie_dctl;
-
-               pcie_dctl_reg += PCI_EXP_DEVCTL;
-               pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
-               pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
-               pcie_dctl |= 0x4000;
-               pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
-       }
+       if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+               pcie_set_readrq(ha->pdev, 2048);
 
        /* Reset expansion ROM address decode enable */
        pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
        d &= ~PCI_ROM_ADDRESS_ENABLE;
        pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
 
-       pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision);
+       ha->chip_revision = ha->pdev->revision;
 
        /* Get PCI bus information. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -306,6 +286,40 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
        return QLA_SUCCESS;
 }
 
+/**
+ * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla25xx_pci_config(scsi_qla_host_t *ha)
+{
+       uint16_t w;
+       uint32_t d;
+
+       pci_set_master(ha->pdev);
+       pci_try_set_mwi(ha->pdev);
+
+       pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+       w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+       w &= ~PCI_COMMAND_INTX_DISABLE;
+       pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+       /* PCIe -- adjust Maximum Read Request Size (2048). */
+       if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+               pcie_set_readrq(ha->pdev, 2048);
+
+       /* Reset expansion ROM address decode enable */
+       pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
+       d &= ~PCI_ROM_ADDRESS_ENABLE;
+       pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+
+       ha->chip_revision = ha->pdev->revision;
+
+       return QLA_SUCCESS;
+}
+
 /**
  * qla2x00_isp_firmware() - Choose firmware image.
  * @ha: HA context
@@ -351,7 +365,7 @@ qla2x00_reset_chip(scsi_qla_host_t *ha)
        uint32_t        cnt;
        uint16_t        cmd;
 
-       ha->isp_ops.disable_intrs(ha);
+       ha->isp_ops->disable_intrs(ha);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -551,7 +565,7 @@ qla24xx_reset_risc(scsi_qla_host_t *ha)
 void
 qla24xx_reset_chip(scsi_qla_host_t *ha)
 {
-       ha->isp_ops.disable_intrs(ha);
+       ha->isp_ops->disable_intrs(ha);
 
        /* Perform RISC reset. */
        qla24xx_reset_risc(ha);
@@ -736,8 +750,10 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
                fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
                mem_size = (ha->fw_memory_size - 0x11000 + 1) *
                    sizeof(uint16_t);
-       } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
-               fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+       } else if (IS_FWI2_CAPABLE(ha)) {
+               fixed_size = IS_QLA25XX(ha) ?
+                   offsetof(struct qla25xx_fw_dump, ext_mem):
+                   offsetof(struct qla24xx_fw_dump, ext_mem);
                mem_size = (ha->fw_memory_size - 0x100000 + 1) *
                    sizeof(uint32_t);
 
@@ -879,7 +895,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
        uint32_t srisc_address = 0;
 
        /* Load firmware sequences */
-       rval = ha->isp_ops.load_risc(ha, &srisc_address);
+       rval = ha->isp_ops->load_risc(ha, &srisc_address);
        if (rval == QLA_SUCCESS) {
                DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
                    "code.\n", ha->host_no));
@@ -899,6 +915,10 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
                                    &ha->fw_subminor_version,
                                    &ha->fw_attributes, &ha->fw_memory_size);
                                qla2x00_resize_request_q(ha);
+                               ha->flags.npiv_supported = 0;
+                               if (IS_QLA24XX(ha) &&
+                                   (ha->fw_attributes & BIT_2))
+                                       ha->flags.npiv_supported = 1;
 
                                if (ql2xallocfwdump)
                                        qla2x00_alloc_fw_dump(ha);
@@ -1101,6 +1121,8 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
        int     rval;
        unsigned long flags = 0;
        int cnt;
+       struct mid_init_cb_24xx *mid_init_cb =
+           (struct mid_init_cb_24xx *) ha->init_cb;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -1124,14 +1146,18 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
        /* Initialize response queue entries */
        qla2x00_init_response_q_entries(ha);
 
-       ha->isp_ops.config_rings(ha);
+       ha->isp_ops->config_rings(ha);
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        /* Update any ISP specific firmware options before initialization. */
-       ha->isp_ops.update_fw_options(ha);
+       ha->isp_ops->update_fw_options(ha);
 
        DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
+
+       mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
+       ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+
        rval = qla2x00_init_firmware(ha, ha->init_cb_size);
        if (rval) {
                DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
@@ -1263,6 +1289,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
        int       rval;
        uint16_t      loop_id;
        uint16_t      topo;
+       uint16_t      sw_cap;
        uint8_t       al_pa;
        uint8_t       area;
        uint8_t       domain;
@@ -1270,7 +1297,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
 
        /* Get host addresses. */
        rval = qla2x00_get_adapter_id(ha,
-           &loop_id, &al_pa, &area, &domain, &topo);
+           &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
        if (rval != QLA_SUCCESS) {
                if (LOOP_TRANSITION(ha) || atomic_read(&ha->loop_down_timer) ||
                    (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
@@ -1295,6 +1322,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
        /* initialize */
        ha->min_external_loopid = SNS_FIRST_LOOP_ID;
        ha->operating_mode = LOOP;
+       ha->switch_cap = 0;
 
        switch (topo) {
        case 0:
@@ -1307,6 +1335,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
        case 1:
                DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
                    ha->host_no));
+               ha->switch_cap = sw_cap;
                ha->current_topology = ISP_CFG_FL;
                strcpy(connect_type, "(FL_Port)");
                break;
@@ -1322,6 +1351,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
        case 3:
                DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
                    ha->host_no));
+               ha->switch_cap = sw_cap;
                ha->operating_mode = P2P;
                ha->current_topology = ISP_CFG_F;
                strcpy(connect_type, "(F_Port)");
@@ -1431,8 +1461,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
        uint16_t        cnt;
        uint8_t         *dptr1, *dptr2;
        init_cb_t       *icb = ha->init_cb;
-       nvram_t         *nv = (nvram_t *)ha->request_ring;
-       uint8_t         *ptr = (uint8_t *)ha->request_ring;
+       nvram_t         *nv = ha->nvram;
+       uint8_t         *ptr = ha->nvram;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        rval = QLA_SUCCESS;
@@ -1445,13 +1475,12 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
                        ha->nvram_base = 0x80;
 
        /* Get NVRAM data and calculate checksum. */
-       ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
+       ha->isp_ops->read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
                chksum += *ptr++;
 
        DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
-           ha->nvram_size));
+       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
@@ -1743,7 +1772,6 @@ qla2x00_rport_del(void *data)
        spin_unlock_irqrestore(&fcport->rport_lock, flags);
        if (rport)
                fc_remote_port_delete(rport);
-
 }
 
 /**
@@ -1765,6 +1793,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
        /* Setup fcport template structure. */
        memset(fcport, 0, sizeof (fc_port_t));
        fcport->ha = ha;
+       fcport->vp_idx = ha->vp_idx;
        fcport->port_type = FCT_UNKNOWN;
        fcport->loop_id = FC_NO_LOOP_ID;
        atomic_set(&fcport->state, FCS_UNCONFIGURED);
@@ -1911,6 +1940,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
        char            *id_iter;
        uint16_t        loop_id;
        uint8_t         domain, area, al_pa;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        found_devs = 0;
        new_fcport = NULL;
@@ -1942,7 +1972,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
        /*
         * Mark local devices that were present with FCF_DEVICE_LOST for now.
         */
-       list_for_each_entry(fcport, &ha->fcports, list) {
+       list_for_each_entry(fcport, &pha->fcports, list) {
+               if (fcport->vp_idx != ha->vp_idx)
+                       continue;
+
                if (atomic_read(&fcport->state) == FCS_ONLINE &&
                    fcport->port_type != FCT_BROADCAST &&
                    (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
@@ -1988,6 +2021,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
                new_fcport->d_id.b.area = area;
                new_fcport->d_id.b.al_pa = al_pa;
                new_fcport->loop_id = loop_id;
+               new_fcport->vp_idx = ha->vp_idx;
                rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
                if (rval2 != QLA_SUCCESS) {
                        DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
@@ -2003,7 +2037,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
                /* Check for matching device in port list. */
                found = 0;
                fcport = NULL;
-               list_for_each_entry(fcport, &ha->fcports, list) {
+               list_for_each_entry(fcport, &pha->fcports, list) {
+                       if (fcport->vp_idx != ha->vp_idx)
+                               continue;
+
                        if (memcmp(new_fcport->port_name, fcport->port_name,
                            WWN_SIZE))
                                continue;
@@ -2023,7 +2060,13 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
                if (!found) {
                        /* New device, add to fcports list. */
                        new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
-                       list_add_tail(&new_fcport->list, &ha->fcports);
+                       if (ha->parent) {
+                               new_fcport->ha = ha;
+                               new_fcport->vp_idx = ha->vp_idx;
+                               list_add_tail(&new_fcport->vp_fcport,
+                                   &ha->vp_fcports);
+                       }
+                       list_add_tail(&new_fcport->list, &pha->fcports);
 
                        /* Allocate a new replacement fcport. */
                        fcport = new_fcport;
@@ -2091,7 +2134,7 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
        int rval;
        uint16_t port_speed, mb[6];
 
-       if (!IS_QLA24XX(ha))
+       if (!IS_IIDMA_CAPABLE(ha))
                return;
 
        switch (be16_to_cpu(fcport->fp_speed)) {
@@ -2199,11 +2242,13 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
 void
 qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
+       scsi_qla_host_t *pha = to_qla_parent(ha);
+
        fcport->ha = ha;
        fcport->login_retry = 0;
-       fcport->port_login_retry_count = ha->port_down_retry_count *
+       fcport->port_login_retry_count = pha->port_down_retry_count *
            PORT_RETRY_TIME;
-       atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+       atomic_set(&fcport->port_down_timer, pha->port_down_retry_count *
            PORT_RETRY_TIME);
        fcport->flags &= ~FCF_LOGIN_NEEDED;
 
@@ -2234,9 +2279,10 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
        uint16_t        mb[MAILBOX_REGISTER_COUNT];
        uint16_t        loop_id;
        LIST_HEAD(new_fcports);
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        /* If FL port exists, then SNS is present */
-       if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+       if (IS_FWI2_CAPABLE(ha))
                loop_id = NPH_F_PORT;
        else
                loop_id = SNS_FL_PORT;
@@ -2263,11 +2309,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                        qla2x00_fdmi_register(ha);
 
                /* Ensure we are logged into the SNS. */
-               if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+               if (IS_FWI2_CAPABLE(ha))
                        loop_id = NPH_SNS;
                else
                        loop_id = SIMPLE_NAME_SERVER;
-               ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff,
+               ha->isp_ops->fabric_login(ha, loop_id, 0xff, 0xff,
                    0xfc, mb, BIT_1 | BIT_0);
                if (mb[0] != MBS_COMMAND_COMPLETE) {
                        DEBUG2(qla_printk(KERN_INFO, ha,
@@ -2307,7 +2353,10 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                 * Logout all previous fabric devices marked lost, except
                 * tape devices.
                 */
-               list_for_each_entry(fcport, &ha->fcports, list) {
+               list_for_each_entry(fcport, &pha->fcports, list) {
+                       if (fcport->vp_idx !=ha->vp_idx)
+                               continue;
+
                        if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
                                break;
 
@@ -2321,7 +2370,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                                    (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
                                    fcport->port_type != FCT_INITIATOR &&
                                    fcport->port_type != FCT_BROADCAST) {
-                                       ha->isp_ops.fabric_logout(ha,
+                                       ha->isp_ops->fabric_logout(ha,
                                            fcport->loop_id,
                                            fcport->d_id.b.domain,
                                            fcport->d_id.b.area,
@@ -2332,13 +2381,16 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                }
 
                /* Starting free loop ID. */
-               next_loopid = ha->min_external_loopid;
+               next_loopid = pha->min_external_loopid;
 
                /*
                 * Scan through our port list and login entries that need to be
                 * logged in.
                 */
-               list_for_each_entry(fcport, &ha->fcports, list) {
+               list_for_each_entry(fcport, &pha->fcports, list) {
+                       if (fcport->vp_idx != ha->vp_idx)
+                               continue;
+
                        if (atomic_read(&ha->loop_down_timer) ||
                            test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
                                break;
@@ -2380,11 +2432,18 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
                                break;
                        }
 
-                       /* Remove device from the new list and add it to DB */
-                       list_move_tail(&fcport->list, &ha->fcports);
-
                        /* Login and update database */
                        qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
+
+                       if (ha->parent) {
+                               fcport->ha = ha;
+                               fcport->vp_idx = ha->vp_idx;
+                               list_add_tail(&fcport->vp_fcport,
+                                   &ha->vp_fcports);
+                               list_move_tail(&fcport->list,
+                                   &ha->parent->fcports);
+                       } else
+                               list_move_tail(&fcport->list, &ha->fcports);
                }
        } while (0);
 
@@ -2428,6 +2487,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
        int             swl_idx;
        int             first_dev, last_dev;
        port_id_t       wrap, nxt_d_id;
+       int             vp_index;
+       int             empty_vp_index;
+       int             found_vp;
+       scsi_qla_host_t *vha;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        rval = QLA_SUCCESS;
 
@@ -2461,13 +2525,13 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
                return (QLA_MEMORY_ALLOC_FAILED);
        }
        new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
-
+       new_fcport->vp_idx = ha->vp_idx;
        /* Set start port ID scan at adapter ID. */
        first_dev = 1;
        last_dev = 0;
 
        /* Starting free loop ID. */
-       loop_id = ha->min_external_loopid;
+       loop_id = pha->min_external_loopid;
        for (; loop_id <= ha->last_loop_id; loop_id++) {
                if (qla2x00_is_reserved_id(ha, loop_id))
                        continue;
@@ -2521,10 +2585,42 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
                        break;
                }
 
-               /* Bypass if host adapter. */
-               if (new_fcport->d_id.b24 == ha->d_id.b24)
+               /* Bypass if same physical adapter. */
+               if (new_fcport->d_id.b24 == pha->d_id.b24)
                        continue;
 
+               /* Bypass virtual ports of the same host. */
+               if (pha->num_vhosts) {
+                       vp_index = find_next_bit(
+                           (unsigned long *)pha->vp_idx_map,
+                           MAX_MULTI_ID_FABRIC + 1, 1);
+
+                       for (;vp_index <= MAX_MULTI_ID_FABRIC;
+                           vp_index = find_next_bit(
+                           (unsigned long *)pha->vp_idx_map,
+                           MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
+                               empty_vp_index = 1;
+                               found_vp = 0;
+                               list_for_each_entry(vha, &pha->vp_list,
+                                   vp_list) {
+                                       if (vp_index == vha->vp_idx) {
+                                               empty_vp_index = 0;
+                                               found_vp = 1;
+                                               break;
+                                       }
+                               }
+
+                               if (empty_vp_index)
+                                       continue;
+
+                               if (found_vp &&
+                                   new_fcport->d_id.b24 == vha->d_id.b24)
+                                       break;
+                       }
+                       if (vp_index <= MAX_MULTI_ID_FABRIC)
+                               continue;
+               }
+
                /* Bypass if same domain and area of adapter. */
                if (((new_fcport->d_id.b24 & 0xffff00) ==
                    (ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
@@ -2537,7 +2633,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
 
                /* Locate matching device in database. */
                found = 0;
-               list_for_each_entry(fcport, &ha->fcports, list) {
+               list_for_each_entry(fcport, &pha->fcports, list) {
+                       if (new_fcport->vp_idx != fcport->vp_idx)
+                               continue;
                        if (memcmp(new_fcport->port_name, fcport->port_name,
                            WWN_SIZE))
                                continue;
@@ -2581,7 +2679,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
                            (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
                            fcport->port_type != FCT_INITIATOR &&
                            fcport->port_type != FCT_BROADCAST) {
-                               ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+                               ha->isp_ops->fabric_logout(ha, fcport->loop_id,
                                    fcport->d_id.b.domain, fcport->d_id.b.area,
                                    fcport->d_id.b.al_pa);
                                fcport->loop_id = FC_NO_LOOP_ID;
@@ -2605,6 +2703,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
                }
                new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
                new_fcport->d_id.b24 = nxt_d_id.b24;
+               new_fcport->vp_idx = ha->vp_idx;
        }
 
        kfree(swl);
@@ -2637,6 +2736,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
        int     found;
        fc_port_t *fcport;
        uint16_t first_loop_id;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        rval = QLA_SUCCESS;
 
@@ -2663,7 +2763,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
                /* Check for loop ID being already in use. */
                found = 0;
                fcport = NULL;
-               list_for_each_entry(fcport, &ha->fcports, list) {
+               list_for_each_entry(fcport, &pha->fcports, list) {
                        if (fcport->loop_id == dev->loop_id && fcport != dev) {
                                /* ID possibly in use */
                                found++;
@@ -2710,6 +2810,7 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
        uint8_t rscn_out_iter;
        uint8_t format;
        port_id_t d_id;
+       scsi_qla_host_t *pha = to_qla_parent(ha);
 
        rval = QLA_RSCNS_HANDLED;
 
@@ -2776,7 +2877,10 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
 
                rval = QLA_SUCCESS;
 
-               list_for_each_entry(fcport, &ha->fcports, list) {
+               list_for_each_entry(fcport, &pha->fcports, list) {
+                       if (fcport->vp_idx != ha->vp_idx)
+                               continue;
+
                        if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
                            (fcport->d_id.b24 & mask) != d_id.b24 ||
                            fcport->port_type == FCT_BROADCAST)
@@ -2830,7 +2934,7 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
                        opts |= BIT_1;
                rval = qla2x00_get_port_database(ha, fcport, opts);
                if (rval != QLA_SUCCESS) {
-                       ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+                       ha->isp_ops->fabric_logout(ha, fcport->loop_id,
                            fcport->d_id.b.domain, fcport->d_id.b.area,
                            fcport->d_id.b.al_pa);
                        qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -2875,7 +2979,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
                    fcport->d_id.b.area, fcport->d_id.b.al_pa));
 
                /* Login fcport on switch. */
-               ha->isp_ops.fabric_login(ha, fcport->loop_id,
+               ha->isp_ops->fabric_login(ha, fcport->loop_id,
                    fcport->d_id.b.domain, fcport->d_id.b.area,
                    fcport->d_id.b.al_pa, mb, BIT_0);
                if (mb[0] == MBS_PORT_ID_USED) {
@@ -2943,7 +3047,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
                         * dead.
                         */
                        *next_loopid = fcport->loop_id;
-                       ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+                       ha->isp_ops->fabric_logout(ha, fcport->loop_id,
                            fcport->d_id.b.domain, fcport->d_id.b.area,
                            fcport->d_id.b.al_pa);
                        qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -2961,7 +3065,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
                            fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
 
                        *next_loopid = fcport->loop_id;
-                       ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+                       ha->isp_ops->fabric_logout(ha, fcport->loop_id,
                            fcport->d_id.b.domain, fcport->d_id.b.area,
                            fcport->d_id.b.al_pa);
                        fcport->loop_id = FC_NO_LOOP_ID;
@@ -3117,7 +3221,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 
                qla_printk(KERN_INFO, ha,
                    "Performing ISP error recovery - ha= %p.\n", ha);
-               ha->isp_ops.reset_chip(ha);
+               ha->isp_ops->reset_chip(ha);
 
                atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
                if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
@@ -3143,9 +3247,9 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                }
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-               ha->isp_ops.get_flash_version(ha, ha->request_ring);
+               ha->isp_ops->get_flash_version(ha, ha->request_ring);
 
-               ha->isp_ops.nvram_config(ha);
+               ha->isp_ops->nvram_config(ha);
 
                if (!qla2x00_restart_isp(ha)) {
                        clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3160,7 +3264,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 
                        ha->flags.online = 1;
 
-                       ha->isp_ops.enable_intrs(ha);
+                       ha->isp_ops->enable_intrs(ha);
 
                        ha->isp_abort_cnt = 0;
                        clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
@@ -3185,7 +3289,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                                         * The next call disables the board
                                         * completely.
                                         */
-                                       ha->isp_ops.reset_adapter(ha);
+                                       ha->isp_ops->reset_adapter(ha);
                                        ha->flags.online = 0;
                                        clear_bit(ISP_ABORT_RETRY,
                                            &ha->dpc_flags);
@@ -3242,7 +3346,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
        /* If firmware needs to be loaded */
        if (qla2x00_isp_firmware(ha)) {
                ha->flags.online = 0;
-               if (!(status = ha->isp_ops.chip_diag(ha))) {
+               if (!(status = ha->isp_ops->chip_diag(ha))) {
                        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
                                status = qla2x00_setup_chip(ha);
                                goto done;
@@ -3334,7 +3438,7 @@ qla2x00_reset_adapter(scsi_qla_host_t *ha)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        ha->flags.online = 0;
-       ha->isp_ops.disable_intrs(ha);
+       ha->isp_ops->disable_intrs(ha);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -3351,7 +3455,7 @@ qla24xx_reset_adapter(scsi_qla_host_t *ha)
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
        ha->flags.online = 0;
-       ha->isp_ops.disable_intrs(ha);
+       ha->isp_ops->disable_intrs(ha);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
@@ -3395,7 +3499,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
 
        rval = QLA_SUCCESS;
        icb = (struct init_cb_24xx *)ha->init_cb;
-       nv = (struct nvram_24xx *)ha->request_ring;
+       nv = ha->nvram;
 
        /* Determine NVRAM starting address. */
        ha->nvram_size = sizeof(struct nvram_24xx);
@@ -3407,16 +3511,20 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
                ha->vpd_base = FA_NVRAM_VPD1_ADDR;
        }
 
-       /* Get NVRAM data and calculate checksum. */
+       /* Get VPD data into cache */
+       ha->vpd = ha->nvram + VPD_OFFSET;
+       ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd,
+           ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
+
+       /* Get NVRAM data into cache and calculate checksum. */
        dptr = (uint32_t *)nv;
-       ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
+       ha->isp_ops->read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
            ha->nvram_size);
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
                chksum += le32_to_cpu(*dptr++);
 
        DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
-           ha->nvram_size));
+       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
@@ -3923,7 +4031,7 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 {
        int ret, retries;
 
-       if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+       if (!IS_FWI2_CAPABLE(ha))
                return;
        if (!ha->fw_major_version)
                return;
@@ -3940,3 +4048,40 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
                ret = qla2x00_stop_firmware(ha);
        }
 }
+
+int
+qla24xx_configure_vhba(scsi_qla_host_t *ha)
+{
+       int rval = QLA_SUCCESS;
+       uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+       if (!ha->parent)
+               return -EINVAL;
+
+       rval = qla2x00_fw_ready(ha);
+       if (rval == QLA_SUCCESS) {
+               clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+               qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
+       }
+
+       ha->flags.management_server_logged_in = 0;
+
+       /* Login to SNS first */
+       qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc,
+           mb, BIT_1);
+       if (mb[0] != MBS_COMMAND_COMPLETE) {
+               DEBUG15(qla_printk(KERN_INFO, ha,
+                   "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
+                   "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
+                   mb[0], mb[1], mb[2], mb[6], mb[7]));
+               return (QLA_FUNCTION_FAILED);
+       }
+
+       atomic_set(&ha->loop_down_timer, 0);
+       atomic_set(&ha->loop_state, LOOP_UP);
+       set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+       set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+       rval = qla2x00_loop_resync(ha);
+
+       return rval;
+}