module_param(msix_vectors, int, S_IRUGO);
 MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
 
+static int allow_vf_ioctls;
+module_param(allow_vf_ioctls, int, S_IRUGO);
+MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
+
 static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
 module_param(throttlequeuedepth, int, S_IRUGO);
 MODULE_PARM_DESC(throttlequeuedepth,
        /* xscale IOP */
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)},
        /* Fusion */
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_PLASMA)},
+       /* Plasma */
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)},
        /* Invader */
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
 MODULE_DEVICE_TABLE(pci, megasas_pci_table);
 
 static int megasas_mgmt_majorno;
-static struct megasas_mgmt_info megasas_mgmt_info;
+struct megasas_mgmt_info megasas_mgmt_info;
 static struct fasync_struct *megasas_async_queue;
 static DEFINE_MUTEX(megasas_async_queue_mutex);
 
 int
 megasas_sync_map_info(struct megasas_instance *instance);
 int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+       int seconds);
 void megasas_reset_reply_desc(struct megasas_instance *instance);
-int megasas_reset_fusion(struct Scsi_Host *shost);
+int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout);
 void megasas_fusion_ocr_wq(struct work_struct *work);
+static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
+                                        int initial);
+int megasas_check_mpio_paths(struct megasas_instance *instance,
+                            struct scsi_cmnd *scmd);
 
 void
 megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
        cmd->scmd = NULL;
        cmd->frame_count = 0;
        if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
+           (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
            (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
            (instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
            (reset_devices))
 int
 megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
+       int seconds;
 
        struct megasas_header *frame_hdr = &cmd->frame->hdr;
 
        /*
         * Wait for cmd_status to change
         */
-       return wait_and_poll(instance, cmd);
+       if (instance->requestorId)
+               seconds = MEGASAS_ROUTINE_WAIT_TIME_VF;
+       else
+               seconds = MFI_POLL_TIMEOUT_SECS;
+       return wait_and_poll(instance, cmd, seconds);
 }
 
 /**
 
        spin_lock_irqsave(&instance->hba_lock, flags);
 
+       /* Check for an mpio path and adjust behavior */
+       if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+               if (megasas_check_mpio_paths(instance, scmd) ==
+                   (DID_RESET << 16)) {
+                       spin_unlock_irqrestore(&instance->hba_lock, flags);
+                       return SCSI_MLQUEUE_HOST_BUSY;
+               } else {
+                       spin_unlock_irqrestore(&instance->hba_lock, flags);
+                       scmd->result = DID_NO_CONNECT << 16;
+                       done(scmd);
+                       return 0;
+               }
+       }
+
        if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
                spin_unlock_irqrestore(&instance->hba_lock, flags);
-               scmd->result = DID_ERROR << 16;
+               scmd->result = DID_NO_CONNECT << 16;
                done(scmd);
                return 0;
        }
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+           (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
                writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
+               /* Flush */
+               readl(&instance->reg_set->doorbell);
+               if (instance->mpio && instance->requestorId)
+                       memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
        } else {
                writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
        }
        megasas_check_and_restore_queue_depth(instance);
 }
 
+/**
+ * megasas_start_timer - Initializes a timer object
+ * @instance:          Adapter soft state
+ * @timer:             timer object to be initialized
+ * @fn:                        timer function
+ * @interval:          time interval between timer function call
+ *
+ */
+void megasas_start_timer(struct megasas_instance *instance,
+                       struct timer_list *timer,
+                       void *fn, unsigned long interval)
+{
+       init_timer(timer);
+       timer->expires = jiffies + interval;
+       timer->data = (unsigned long)instance;
+       timer->function = fn;
+       add_timer(timer);
+}
+
 static void
 megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
 
        process_fw_state_change_wq(&instance->work_init);
 }
 
+/* This function will get the current SR-IOV LD/VF affiliation */
+static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
+       int initial)
+{
+       struct megasas_cmd *cmd;
+       struct megasas_dcmd_frame *dcmd;
+       struct MR_LD_VF_AFFILIATION *new_affiliation = NULL;
+       struct MR_LD_VF_AFFILIATION_111 *new_affiliation_111 = NULL;
+       struct MR_LD_VF_MAP *newmap = NULL, *savedmap = NULL;
+       dma_addr_t new_affiliation_h;
+       dma_addr_t new_affiliation_111_h;
+       int ld, retval = 0;
+       u8 thisVf;
+
+       cmd = megasas_get_cmd(instance);
+
+       if (!cmd) {
+               printk(KERN_DEBUG "megasas: megasas_get_ld_vf_"
+                      "affiliation: Failed to get cmd for scsi%d.\n",
+                       instance->host->host_no);
+               return -ENOMEM;
+       }
+
+       dcmd = &cmd->frame->dcmd;
+
+       if (!instance->vf_affiliation && !instance->vf_affiliation_111) {
+               printk(KERN_WARNING "megasas: SR-IOV: Couldn't get LD/VF "
+                      "affiliation for scsi%d.\n", instance->host->host_no);
+               megasas_return_cmd(instance, cmd);
+               return -ENOMEM;
+       }
+
+       if (initial)
+               if (instance->PlasmaFW111)
+                       memset(instance->vf_affiliation_111, 0,
+                              sizeof(struct MR_LD_VF_AFFILIATION_111));
+               else
+                       memset(instance->vf_affiliation, 0,
+                              (MAX_LOGICAL_DRIVES + 1) *
+                              sizeof(struct MR_LD_VF_AFFILIATION));
+       else {
+               if (instance->PlasmaFW111)
+                       new_affiliation_111 =
+                               pci_alloc_consistent(instance->pdev,
+                                                    sizeof(struct MR_LD_VF_AFFILIATION_111),
+                                                    &new_affiliation_111_h);
+               else
+                       new_affiliation =
+                               pci_alloc_consistent(instance->pdev,
+                                                    (MAX_LOGICAL_DRIVES + 1) *
+                                                    sizeof(struct MR_LD_VF_AFFILIATION),
+                                                    &new_affiliation_h);
+               if (!new_affiliation && !new_affiliation_111) {
+                       printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate "
+                              "memory for new affiliation for scsi%d.\n",
+                               instance->host->host_no);
+                       megasas_return_cmd(instance, cmd);
+                       return -ENOMEM;
+               }
+               if (instance->PlasmaFW111)
+                       memset(new_affiliation_111, 0,
+                              sizeof(struct MR_LD_VF_AFFILIATION_111));
+               else
+                       memset(new_affiliation, 0, (MAX_LOGICAL_DRIVES + 1) *
+                              sizeof(struct MR_LD_VF_AFFILIATION));
+       }
+
+       memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+       dcmd->cmd = MFI_CMD_DCMD;
+       dcmd->cmd_status = 0xFF;
+       dcmd->sge_count = 1;
+       dcmd->flags = MFI_FRAME_DIR_BOTH;
+       dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
+       if (instance->PlasmaFW111) {
+               dcmd->data_xfer_len = sizeof(struct MR_LD_VF_AFFILIATION_111);
+               dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111;
+       } else {
+               dcmd->data_xfer_len = (MAX_LOGICAL_DRIVES + 1) *
+                       sizeof(struct MR_LD_VF_AFFILIATION);
+               dcmd->opcode = MR_DCMD_LD_VF_MAP_GET_ALL_LDS;
+       }
+
+       if (initial) {
+               if (instance->PlasmaFW111)
+                       dcmd->sgl.sge32[0].phys_addr =
+                         instance->vf_affiliation_111_h;
+               else
+                       dcmd->sgl.sge32[0].phys_addr =
+                         instance->vf_affiliation_h;
+       } else {
+               if (instance->PlasmaFW111)
+                       dcmd->sgl.sge32[0].phys_addr = new_affiliation_111_h;
+               else
+                       dcmd->sgl.sge32[0].phys_addr = new_affiliation_h;
+       }
+       if (instance->PlasmaFW111)
+               dcmd->sgl.sge32[0].length =
+                 sizeof(struct MR_LD_VF_AFFILIATION_111);
+       else
+               dcmd->sgl.sge32[0].length = (MAX_LOGICAL_DRIVES + 1) *
+                       sizeof(struct MR_LD_VF_AFFILIATION);
+
+       printk(KERN_WARNING "megasas: SR-IOV: Getting LD/VF affiliation for "
+              "scsi%d\n", instance->host->host_no);
+
+       megasas_issue_blocked_cmd(instance, cmd, 0);
+
+       if (dcmd->cmd_status) {
+               printk(KERN_WARNING "megasas: SR-IOV: LD/VF affiliation DCMD"
+                      " failed with status 0x%x for scsi%d.\n",
+                      dcmd->cmd_status, instance->host->host_no);
+               retval = 1; /* Do a scan if we couldn't get affiliation */
+               goto out;
+       }
+
+       if (!initial) {
+               if (instance->PlasmaFW111) {
+                       if (!new_affiliation_111->vdCount) {
+                               printk(KERN_WARNING "megasas: SR-IOV: Got new "
+                                      "LD/VF affiliation for passive path "
+                                      "for scsi%d.\n",
+                                       instance->host->host_no);
+                               retval = 1;
+                               goto out;
+                       }
+                       thisVf = new_affiliation_111->thisVf;
+                       for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++)
+                               if (instance->vf_affiliation_111->map[ld].policy[thisVf] != new_affiliation_111->map[ld].policy[thisVf]) {
+                                       printk(KERN_WARNING "megasas: SR-IOV: "
+                                              "Got new LD/VF affiliation "
+                                              "for scsi%d.\n",
+                                               instance->host->host_no);
+                                       memcpy(instance->vf_affiliation_111,
+                                              new_affiliation_111,
+                                              sizeof(struct MR_LD_VF_AFFILIATION_111));
+                                       retval = 1;
+                                       goto out;
+                               }
+               } else {
+                       if (!new_affiliation->ldCount) {
+                               printk(KERN_WARNING "megasas: SR-IOV: Got new "
+                                      "LD/VF affiliation for passive "
+                                      "path for scsi%d.\n",
+                                      instance->host->host_no);
+                               retval = 1;
+                               goto out;
+                       }
+                       newmap = new_affiliation->map;
+                       savedmap = instance->vf_affiliation->map;
+                       thisVf = new_affiliation->thisVf;
+                       for (ld = 0 ; ld < new_affiliation->ldCount; ld++) {
+                               if (savedmap->policy[thisVf] !=
+                                   newmap->policy[thisVf]) {
+                                       printk(KERN_WARNING "megasas: SR-IOV: "
+                                              "Got new LD/VF affiliation "
+                                              "for scsi%d.\n",
+                                               instance->host->host_no);
+                                       memcpy(instance->vf_affiliation,
+                                              new_affiliation,
+                                              new_affiliation->size);
+                                       retval = 1;
+                                       goto out;
+                               }
+                               savedmap = (struct MR_LD_VF_MAP *)
+                                       ((unsigned char *)savedmap +
+                                        savedmap->size);
+                               newmap = (struct MR_LD_VF_MAP *)
+                                       ((unsigned char *)newmap +
+                                        newmap->size);
+                       }
+               }
+       }
+out:
+       if (new_affiliation) {
+               if (instance->PlasmaFW111)
+                       pci_free_consistent(instance->pdev,
+                                           sizeof(struct MR_LD_VF_AFFILIATION_111),
+                                           new_affiliation_111,
+                                           new_affiliation_111_h);
+               else
+                       pci_free_consistent(instance->pdev,
+                                           (MAX_LOGICAL_DRIVES + 1) *
+                                           sizeof(struct MR_LD_VF_AFFILIATION),
+                                           new_affiliation, new_affiliation_h);
+       }
+       megasas_return_cmd(instance, cmd);
+
+       return retval;
+}
+
+/* This function will tell FW to start the SR-IOV heartbeat */
+int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
+                                        int initial)
+{
+       struct megasas_cmd *cmd;
+       struct megasas_dcmd_frame *dcmd;
+       int retval = 0;
+
+       cmd = megasas_get_cmd(instance);
+
+       if (!cmd) {
+               printk(KERN_DEBUG "megasas: megasas_sriov_start_heartbeat: "
+                      "Failed to get cmd for scsi%d.\n",
+                      instance->host->host_no);
+               return -ENOMEM;
+       }
+
+       dcmd = &cmd->frame->dcmd;
+
+       if (initial) {
+               instance->hb_host_mem =
+                       pci_alloc_consistent(instance->pdev,
+                                            sizeof(struct MR_CTRL_HB_HOST_MEM),
+                                            &instance->hb_host_mem_h);
+               if (!instance->hb_host_mem) {
+                       printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate"
+                              " memory for heartbeat host memory for "
+                              "scsi%d.\n", instance->host->host_no);
+                       retval = -ENOMEM;
+                       goto out;
+               }
+               memset(instance->hb_host_mem, 0,
+                      sizeof(struct MR_CTRL_HB_HOST_MEM));
+       }
+
+       memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+       dcmd->mbox.s[0] = sizeof(struct MR_CTRL_HB_HOST_MEM);
+       dcmd->cmd = MFI_CMD_DCMD;
+       dcmd->cmd_status = 0xFF;
+       dcmd->sge_count = 1;
+       dcmd->flags = MFI_FRAME_DIR_BOTH;
+       dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
+       dcmd->data_xfer_len = sizeof(struct MR_CTRL_HB_HOST_MEM);
+       dcmd->opcode = MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC;
+       dcmd->sgl.sge32[0].phys_addr = instance->hb_host_mem_h;
+       dcmd->sgl.sge32[0].length = sizeof(struct MR_CTRL_HB_HOST_MEM);
+
+       printk(KERN_WARNING "megasas: SR-IOV: Starting heartbeat for scsi%d\n",
+              instance->host->host_no);
+
+       if (!megasas_issue_polled(instance, cmd)) {
+               retval = 0;
+       } else {
+               printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
+                      "_MEM_ALLOC DCMD timed out for scsi%d\n",
+                      instance->host->host_no);
+               retval = 1;
+               goto out;
+       }
+
+
+       if (dcmd->cmd_status) {
+               printk(KERN_WARNING "megasas: SR-IOV: MR_DCMD_CTRL_SHARED_HOST"
+                      "_MEM_ALLOC DCMD failed with status 0x%x for scsi%d\n",
+                      dcmd->cmd_status,
+                      instance->host->host_no);
+               retval = 1;
+               goto out;
+       }
+
+out:
+       megasas_return_cmd(instance, cmd);
+
+       return retval;
+}
+
+/* Handler for SR-IOV heartbeat */
+void megasas_sriov_heartbeat_handler(unsigned long instance_addr)
+{
+       struct megasas_instance *instance =
+               (struct megasas_instance *)instance_addr;
+
+       if (instance->hb_host_mem->HB.fwCounter !=
+           instance->hb_host_mem->HB.driverCounter) {
+               instance->hb_host_mem->HB.driverCounter =
+                       instance->hb_host_mem->HB.fwCounter;
+               mod_timer(&instance->sriov_heartbeat_timer,
+                         jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+       } else {
+               printk(KERN_WARNING "megasas: SR-IOV: Heartbeat never "
+                      "completed for scsi%d\n", instance->host->host_no);
+               schedule_work(&instance->work_init);
+       }
+}
+
 /**
  * megasas_wait_for_outstanding -      Wait for all outstanding cmds
  * @instance:                          Adapter soft state
         * First wait for all commands to complete
         */
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+           (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
-               ret = megasas_reset_fusion(scmd->device->host);
+               ret = megasas_reset_fusion(scmd->device->host, 1);
        else
                ret = megasas_generic_reset(scmd);
 
                                (instance->pdev->device ==
                                PCI_DEVICE_ID_LSI_FUSION) ||
                                (instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_PLASMA) ||
+                               (instance->pdev->device ==
                                PCI_DEVICE_ID_LSI_INVADER) ||
                                (instance->pdev->device ==
                                PCI_DEVICE_ID_LSI_FURY)) {
                                 PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
                            (instance->pdev->device ==
                             PCI_DEVICE_ID_LSI_FUSION) ||
+                           (instance->pdev->device ==
+                            PCI_DEVICE_ID_LSI_PLASMA) ||
                            (instance->pdev->device ==
                             PCI_DEVICE_ID_LSI_INVADER) ||
                            (instance->pdev->device ==
                                PCI_DEVICE_ID_LSI_SAS0071SKINNY)  ||
                                (instance->pdev->device
                                        == PCI_DEVICE_ID_LSI_FUSION) ||
+                               (instance->pdev->device
+                                       == PCI_DEVICE_ID_LSI_PLASMA) ||
                                (instance->pdev->device
                                        == PCI_DEVICE_ID_LSI_INVADER) ||
                                (instance->pdev->device
                                if ((instance->pdev->device ==
                                        PCI_DEVICE_ID_LSI_FUSION) ||
                                        (instance->pdev->device ==
+                                       PCI_DEVICE_ID_LSI_PLASMA) ||
+                                       (instance->pdev->device ==
                                        PCI_DEVICE_ID_LSI_INVADER) ||
                                        (instance->pdev->device ==
                                        PCI_DEVICE_ID_LSI_FURY)) {
                cmd->frame->io.context = cpu_to_le32(cmd->index);
                cmd->frame->io.pad_0 = 0;
                if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
+                   (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
                    (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
                        (instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
                    (reset_devices))
        struct megasas_ctrl_info *ctrl_info;
        unsigned long bar_list;
        int i, loop, fw_msix_count = 0;
+       struct IOV_111 *iovPtr;
 
        /* Find first memory bar */
        bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_PLASMA:
        case PCI_DEVICE_ID_LSI_INVADER:
        case PCI_DEVICE_ID_LSI_FURY:
                instance->instancet = &megasas_instance_template_fusion;
                scratch_pad_2 = readl
                        (&instance->reg_set->outbound_scratch_pad_2);
                /* Check max MSI-X vectors */
-               if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) {
+               if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+                   (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) {
                        instance->msix_vectors = (scratch_pad_2
                                & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
                        fw_msix_count = instance->msix_vectors;
                ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
                /* adapterOperations2 are converted into CPU arch*/
                le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
+               instance->mpio = ctrl_info->adapterOperations2.mpio;
                instance->UnevenSpanSupport =
                        ctrl_info->adapterOperations2.supportUnevenSpans;
                if (instance->UnevenSpanSupport) {
                                fusion->fast_path_io = 0;
 
                }
+               if (ctrl_info->host_interface.SRIOV) {
+                       if (!ctrl_info->adapterOperations2.activePassive)
+                               instance->PlasmaFW111 = 1;
+
+                       if (!instance->PlasmaFW111)
+                               instance->requestorId =
+                                       ctrl_info->iov.requestorId;
+                       else {
+                               iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET);
+                               instance->requestorId = iovPtr->requestorId;
+                       }
+                       printk(KERN_WARNING "megaraid_sas: I am VF "
+                              "requestorId %d\n", instance->requestorId);
+               }
        }
        instance->max_sectors_per_req = instance->max_num_sge *
                                                PAGE_SIZE / 512;
        tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
                (unsigned long)instance);
 
+       /* Launch SR-IOV heartbeat timer */
+       if (instance->requestorId) {
+               if (!megasas_sriov_start_heartbeat(instance, 1))
+                       megasas_start_timer(instance,
+                                           &instance->sriov_heartbeat_timer,
+                                           megasas_sriov_heartbeat_handler,
+                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+               else
+                       instance->skip_heartbeat_timer_del = 1;
+       }
+
        return 0;
 
 fail_init_adapter:
 
        /* Fusion only supports host reset */
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+           (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
                host->hostt->eh_device_reset_handler = NULL;
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_PLASMA:
        case PCI_DEVICE_ID_LSI_INVADER:
        case PCI_DEVICE_ID_LSI_FURY:
        {
        instance->UnevenSpanSupport = 0;
 
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+           (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
                INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
        if (megasas_init_fw(instance))
                goto fail_init_mfi;
 
+       if (instance->requestorId) {
+               if (instance->PlasmaFW111) {
+                       instance->vf_affiliation_111 =
+                               pci_alloc_consistent(pdev, sizeof(struct MR_LD_VF_AFFILIATION_111),
+                                                    &instance->vf_affiliation_111_h);
+                       if (!instance->vf_affiliation_111)
+                               printk(KERN_WARNING "megasas: Can't allocate "
+                                      "memory for VF affiliation buffer\n");
+               } else {
+                       instance->vf_affiliation =
+                               pci_alloc_consistent(pdev,
+                                                    (MAX_LOGICAL_DRIVES + 1) *
+                                                    sizeof(struct MR_LD_VF_AFFILIATION),
+                                                    &instance->vf_affiliation_h);
+                       if (!instance->vf_affiliation)
+                               printk(KERN_WARNING "megasas: Can't allocate "
+                                      "memory for VF affiliation buffer\n");
+               }
+       }
+
 retry_irq_register:
        /*
         * Register IRQ
                free_irq(instance->pdev->irq, &instance->irq_context[0]);
 fail_irq:
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+           (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
            (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
                megasas_release_fusion(instance);
        host = instance->host;
        instance->unload = 1;
 
+       /* Shutdown SR-IOV heartbeat timer */
+       if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+               del_timer_sync(&instance->sriov_heartbeat_timer);
+
        megasas_flush_cache(instance);
        megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
 
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_PLASMA:
        case PCI_DEVICE_ID_LSI_INVADER:
        case PCI_DEVICE_ID_LSI_FURY:
        {
                }
        }
 
+       /* Re-launch SR-IOV heartbeat timer */
+       if (instance->requestorId) {
+               if (!megasas_sriov_start_heartbeat(instance, 0))
+                       megasas_start_timer(instance,
+                                           &instance->sriov_heartbeat_timer,
+                                           megasas_sriov_heartbeat_handler,
+                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+               else
+                       instance->skip_heartbeat_timer_del = 1;
+       }
+
        instance->instancet->enable_intr(instance);
        instance->unload = 0;
 
        host = instance->host;
        fusion = instance->ctrl_context;
 
+       /* Shutdown SR-IOV heartbeat timer */
+       if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+               del_timer_sync(&instance->sriov_heartbeat_timer);
+
        scsi_remove_host(instance->host);
        megasas_flush_cache(instance);
        megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_PLASMA:
        case PCI_DEVICE_ID_LSI_INVADER:
        case PCI_DEVICE_ID_LSI_FURY:
                megasas_release_fusion(instance);
        if (instance->evt_detail)
                pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
                                instance->evt_detail, instance->evt_detail_h);
+
+       if (instance->vf_affiliation)
+               pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
+                                   sizeof(struct MR_LD_VF_AFFILIATION),
+                                   instance->vf_affiliation,
+                                   instance->vf_affiliation_h);
+
+       if (instance->vf_affiliation_111)
+               pci_free_consistent(pdev,
+                                   sizeof(struct MR_LD_VF_AFFILIATION_111),
+                                   instance->vf_affiliation_111,
+                                   instance->vf_affiliation_111_h);
+
+       if (instance->hb_host_mem)
+               pci_free_consistent(pdev, sizeof(struct MR_CTRL_HB_HOST_MEM),
+                                   instance->hb_host_mem,
+                                   instance->hb_host_mem_h);
+
        scsi_host_put(host);
 
        pci_disable_device(pdev);
                goto out_kfree_ioc;
        }
 
+       /* Adjust ioctl wait time for VF mode */
+       if (instance->requestorId)
+               wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
+
+       /* Block ioctls in VF mode */
+       if (instance->requestorId && !allow_vf_ioctls) {
+               error = -ENODEV;
+               goto out_kfree_ioc;
+       }
+
        if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
                printk(KERN_ERR "Controller in crit error\n");
                error = -ENODEV;
        u16     pd_index = 0;
        u16     ld_index = 0;
        int     i, j, doscan = 0;
-       u32 seq_num;
+       u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
        int error;
 
        if (!instance) {
                kfree(ev);
                return;
        }
+
+       /* Adjust event workqueue thread wait time for VF mode */
+       if (instance->requestorId)
+               wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
+
+       /* Don't run the event workqueue thread if OCR is running */
+       for (i = 0; i < wait_time; i++) {
+               if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)
+                       break;
+               if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+                       printk(KERN_NOTICE "megasas: %s waiting for "
+                              "controller reset to finish for scsi%d\n",
+                              __func__, instance->host->host_no);
+               }
+               msleep(1000);
+       }
+
        instance->ev = NULL;
        host = instance->host;
        if (instance->evt_detail) {
                case MR_EVT_LD_OFFLINE:
                case MR_EVT_CFG_CLEARED:
                case MR_EVT_LD_DELETED:
-                       if (megasas_ld_list_query(instance,
-                                       MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-                               megasas_get_ld_list(instance);
-                       for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-                               for (j = 0;
-                               j < MEGASAS_MAX_DEV_PER_CHANNEL;
-                               j++) {
-
-                               ld_index =
-                               (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-                               sdev1 = scsi_device_lookup(host,
-                                       MEGASAS_MAX_PD_CHANNELS + i,
-                                       j,
-                                       0);
-
-                               if (instance->ld_ids[ld_index] != 0xff) {
-                                       if (sdev1) {
-                                               scsi_device_put(sdev1);
-                                       }
-                               } else {
-                                       if (sdev1) {
-                                               scsi_remove_device(sdev1);
-                                               scsi_device_put(sdev1);
+                       if (!instance->requestorId ||
+                           (instance->requestorId &&
+                            megasas_get_ld_vf_affiliation(instance, 0))) {
+                               if (megasas_ld_list_query(instance,
+                                                         MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+                                       megasas_get_ld_list(instance);
+                               for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+                                       for (j = 0;
+                                            j < MEGASAS_MAX_DEV_PER_CHANNEL;
+                                            j++) {
+
+                                               ld_index =
+                                                       (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+                                               sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+
+                                               if (instance->ld_ids[ld_index]
+                                                   != 0xff) {
+                                                       if (sdev1)
+                                                               scsi_device_put(sdev1);
+                                               } else {
+                                                       if (sdev1) {
+                                                               scsi_remove_device(sdev1);
+                                                               scsi_device_put(sdev1);
+                                                       }
+                                               }
                                        }
                                }
-                               }
+                               doscan = 0;
                        }
-                       doscan = 0;
                        break;
                case MR_EVT_LD_CREATED:
-                       if (megasas_ld_list_query(instance,
-                                       MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-                               megasas_get_ld_list(instance);
-                       for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-                               for (j = 0;
-                                       j < MEGASAS_MAX_DEV_PER_CHANNEL;
-                                       j++) {
-                                       ld_index =
-                                       (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
-
-                                       sdev1 = scsi_device_lookup(host,
-                                               MEGASAS_MAX_PD_CHANNELS + i,
-                                               j, 0);
-
-                                       if (instance->ld_ids[ld_index] !=
-                                                               0xff) {
-                                               if (!sdev1) {
-                                                       scsi_add_device(host,
-                                               MEGASAS_MAX_PD_CHANNELS + i,
-                                                               j, 0);
+                       if (!instance->requestorId ||
+                           (instance->requestorId &&
+                            megasas_get_ld_vf_affiliation(instance, 0))) {
+                               if (megasas_ld_list_query(instance,
+                                                         MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+                                       megasas_get_ld_list(instance);
+                               for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+                                       for (j = 0;
+                                            j < MEGASAS_MAX_DEV_PER_CHANNEL;
+                                            j++) {
+                                               ld_index =
+                                                       (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+
+                                               sdev1 = scsi_device_lookup(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+
+                                               if (instance->ld_ids[ld_index]
+                                                   != 0xff) {
+                                                       if (!sdev1)
+                                                               scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
                                                }
-                                       }
-                                       if (sdev1) {
-                                               scsi_device_put(sdev1);
+                                               if (sdev1)
+                                                       scsi_device_put(sdev1);
                                        }
                                }
+                               doscan = 0;
                        }
-                       doscan = 0;
                        break;
                case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
                case MR_EVT_FOREIGN_CFG_IMPORTED:
        }
 
        if (doscan) {
-               printk(KERN_INFO "scanning ...\n");
+               printk(KERN_INFO "megaraid_sas: scanning for scsi%d...\n",
+                      instance->host->host_no);
                if (megasas_get_pd_list(instance) == 0) {
                        for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
                                for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
                        }
                }
 
-               if (megasas_ld_list_query(instance,
-                                         MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-                       megasas_get_ld_list(instance);
-               for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
-                       for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
-                               ld_index =
-                               (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+               if (!instance->requestorId ||
+                   (instance->requestorId &&
+                    megasas_get_ld_vf_affiliation(instance, 0))) {
+                       if (megasas_ld_list_query(instance,
+                                                 MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+                               megasas_get_ld_list(instance);
+                       for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
+                               for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL;
+                                    j++) {
+                                       ld_index =
+                                               (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
 
-                               sdev1 = scsi_device_lookup(host,
-                                       MEGASAS_MAX_PD_CHANNELS + i, j, 0);
-                               if (instance->ld_ids[ld_index] != 0xff) {
-                                       if (!sdev1) {
-                                               scsi_add_device(host,
-                                               MEGASAS_MAX_PD_CHANNELS + i,
-                                                               j, 0);
+                                       sdev1 = scsi_device_lookup(host,
+                                                                  MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+                                       if (instance->ld_ids[ld_index]
+                                           != 0xff) {
+                                               if (!sdev1)
+                                                       scsi_add_device(host, MEGASAS_MAX_PD_CHANNELS + i, j, 0);
+                                               else
+                                                       scsi_device_put(sdev1);
                                        } else {
-                                               scsi_device_put(sdev1);
-                                       }
-                               } else {
-                                       if (sdev1) {
-                                               scsi_remove_device(sdev1);
-                                               scsi_device_put(sdev1);
+                                               if (sdev1) {
+                                                       scsi_remove_device(sdev1);
+                                                       scsi_device_put(sdev1);
+                                               }
                                        }
                                }
                        }
 
                     struct megasas_cmd *cmd, u8 alt_status);
 int megasas_is_ldio(struct scsi_cmnd *cmd);
 int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd);
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+             int seconds);
 
 void
 megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd);
 void megaraid_sas_kill_hba(struct megasas_instance *instance);
 
 extern u32 megasas_dbg_lvl;
+void megasas_sriov_heartbeat_handler(unsigned long instance_addr);
+int megasas_sriov_start_heartbeat(struct megasas_instance *instance,
+                                 int initial);
+void megasas_start_timer(struct megasas_instance *instance,
+                       struct timer_list *timer,
+                        void *fn, unsigned long interval);
+extern struct megasas_mgmt_info megasas_mgmt_info;
 extern int resetwaittime;
 
 /**
  * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
  */
 int
-wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd)
+wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
+       int seconds)
 {
        int i;
        struct megasas_header *frame_hdr = &cmd->frame->hdr;
 
-       u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+       u32 msecs = seconds * 1000;
 
        /*
         * Wait for cmd_status to change
        instance->instancet->fire_cmd(instance, req_desc.u.low,
                                      req_desc.u.high, instance->reg_set);
 
-       wait_and_poll(instance, cmd);
+       wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS);
 
        frame_hdr = &cmd->frame->hdr;
        if (frame_hdr->cmd_status != 0) {
 
        if (index >= instance->max_fw_cmds) {
                printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for "
-                      "descriptor\n", index);
+                      "descriptor for scsi%d\n", index,
+                       instance->host->host_no);
                return NULL;
        }
        fusion = instance->ctrl_context;
                /* If we didn't complete any commands, check for FW fault */
                fw_state = instance->instancet->read_fw_status_reg(
                        instance->reg_set) & MFI_STATE_MASK;
-               if (fw_state == MFI_STATE_FAULT)
+               if (fw_state == MFI_STATE_FAULT) {
+                       printk(KERN_WARNING "megaraid_sas: Iop2SysDoorbellInt"
+                              "for scsi%d\n", instance->host->host_no);
                        schedule_work(&instance->work_init);
+               }
        }
 
        return IRQ_HANDLED;
 }
 
 /* This function waits for outstanding commands on fusion to complete */
-int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
+int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
+                                       int iotimeout, int *convert)
 {
-       int i, outstanding, retval = 0;
+       int i, outstanding, retval = 0, hb_seconds_missed = 0;
        u32 fw_state;
 
        for (i = 0; i < resetwaittime; i++) {
                        instance->reg_set) & MFI_STATE_MASK;
                if (fw_state == MFI_STATE_FAULT) {
                        printk(KERN_WARNING "megasas: Found FW in FAULT state,"
-                              " will reset adapter.\n");
+                              " will reset adapter scsi%d.\n",
+                               instance->host->host_no);
+                       retval = 1;
+                       goto out;
+               }
+               /* If SR-IOV VF mode & heartbeat timeout, don't wait */
+               if (instance->requestorId && !iotimeout) {
                        retval = 1;
                        goto out;
                }
 
+               /* If SR-IOV VF mode & I/O timeout, check for HB timeout */
+               if (instance->requestorId && iotimeout) {
+                       if (instance->hb_host_mem->HB.fwCounter !=
+                           instance->hb_host_mem->HB.driverCounter) {
+                               instance->hb_host_mem->HB.driverCounter =
+                                       instance->hb_host_mem->HB.fwCounter;
+                               hb_seconds_missed = 0;
+                       } else {
+                               hb_seconds_missed++;
+                               if (hb_seconds_missed ==
+                                   (MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF/HZ)) {
+                                       printk(KERN_WARNING "megasas: SR-IOV:"
+                                              " Heartbeat never completed "
+                                              " while polling during I/O "
+                                              " timeout handling for "
+                                              "scsi%d.\n",
+                                              instance->host->host_no);
+                                              *convert = 1;
+                                              retval = 1;
+                                              goto out;
+                               }
+                       }
+               }
+
                outstanding = atomic_read(&instance->fw_outstanding);
                if (!outstanding)
                        goto out;
 
                if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
                        printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
-                              "commands to complete\n", i, outstanding);
+                              "commands to complete for scsi%d\n", i,
+                              outstanding, instance->host->host_no);
                        megasas_complete_cmd_dpc_fusion(
                                (unsigned long)instance);
                }
 
        if (atomic_read(&instance->fw_outstanding)) {
                printk("megaraid_sas: pending commands remain after waiting, "
-                      "will reset adapter.\n");
+                      "will reset adapter scsi%d.\n",
+                      instance->host->host_no);
                retval = 1;
        }
 out:
                reply_desc->Words = ULLONG_MAX;
 }
 
+/* Check for a second path that is currently UP */
+int megasas_check_mpio_paths(struct megasas_instance *instance,
+       struct scsi_cmnd *scmd)
+{
+       int i, j, retval = (DID_RESET << 16);
+
+       if (instance->mpio && instance->requestorId) {
+               for (i = 0 ; i < MAX_MGMT_ADAPTERS ; i++)
+                       for (j = 0 ; j < MAX_LOGICAL_DRIVES; j++)
+                               if (megasas_mgmt_info.instance[i] &&
+                                   (megasas_mgmt_info.instance[i] != instance) &&
+                                   megasas_mgmt_info.instance[i]->mpio &&
+                                   megasas_mgmt_info.instance[i]->requestorId
+                                   &&
+                                   (megasas_mgmt_info.instance[i]->ld_ids[j]
+                                    == scmd->device->id)) {
+                                           retval = (DID_NO_CONNECT << 16);
+                                           goto out;
+                               }
+       }
+out:
+       return retval;
+}
+
 /* Core fusion reset function */
-int megasas_reset_fusion(struct Scsi_Host *shost)
+int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 {
-       int retval = SUCCESS, i, j, retry = 0;
+       int retval = SUCCESS, i, j, retry = 0, convert = 0;
        struct megasas_instance *instance;
        struct megasas_cmd_fusion *cmd_fusion;
        struct fusion_context *fusion;
        instance = (struct megasas_instance *)shost->hostdata;
        fusion = instance->ctrl_context;
 
+       mutex_lock(&instance->reset_mutex);
+
        if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
                printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
-                      "returning FAILED.\n");
+                      "returning FAILED for scsi%d.\n",
+                       instance->host->host_no);
                return FAILED;
        }
 
-       mutex_lock(&instance->reset_mutex);
+       if (instance->requestorId && !instance->skip_heartbeat_timer_del)
+               del_timer_sync(&instance->sriov_heartbeat_timer);
        set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
-       instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+       instance->adprecovery = MEGASAS_ADPRESET_SM_POLLING;
        instance->instancet->disable_intr(instance);
        msleep(1000);
 
        /* First try waiting for commands to complete */
-       if (megasas_wait_for_outstanding_fusion(instance)) {
+       if (megasas_wait_for_outstanding_fusion(instance, iotimeout,
+                                               &convert)) {
+               instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
                printk(KERN_WARNING "megaraid_sas: resetting fusion "
-                      "adapter.\n");
+                      "adapter scsi%d.\n", instance->host->host_no);
+               if (convert)
+                       iotimeout = 0;
+
                /* Now return commands back to the OS */
                for (i = 0 ; i < instance->max_fw_cmds; i++) {
                        cmd_fusion = fusion->cmd_list[i];
                        if (cmd_fusion->scmd) {
                                scsi_dma_unmap(cmd_fusion->scmd);
-                               cmd_fusion->scmd->result = (DID_RESET << 16);
+                               cmd_fusion->scmd->result =
+                                       megasas_check_mpio_paths(instance,
+                                                                cmd_fusion->scmd);
                                cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
                                megasas_return_cmd_fusion(instance, cmd_fusion);
                                atomic_dec(&instance->fw_outstanding);
                    (abs_state == MFI_STATE_FAULT && !reset_adapter)) {
                        /* Reset not supported, kill adapter */
                        printk(KERN_WARNING "megaraid_sas: Reset not supported"
-                              ", killing adapter.\n");
+                              ", killing adapter scsi%d.\n",
+                               instance->host->host_no);
                        megaraid_sas_kill_hba(instance);
+                       instance->skip_heartbeat_timer_del = 1;
                        instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
                        retval = FAILED;
                        goto out;
                }
 
+               /* Let SR-IOV VF & PF sync up if there was a HB failure */
+               if (instance->requestorId && !iotimeout) {
+                       msleep(MEGASAS_OCR_SETTLE_TIME_VF);
+                       /* Look for a late HB update after VF settle time */
+                       if (abs_state == MFI_STATE_OPERATIONAL &&
+                           (instance->hb_host_mem->HB.fwCounter !=
+                            instance->hb_host_mem->HB.driverCounter)) {
+                                       instance->hb_host_mem->HB.driverCounter =
+                                               instance->hb_host_mem->HB.fwCounter;
+                                       printk(KERN_WARNING "megasas: SR-IOV:"
+                                              "Late FW heartbeat update for "
+                                              "scsi%d.\n",
+                                              instance->host->host_no);
+                       } else {
+                               /* In VF mode, first poll for FW ready */
+                               for (i = 0;
+                                    i < (MEGASAS_RESET_WAIT_TIME * 1000);
+                                    i += 20) {
+                                       status_reg =
+                                               instance->instancet->
+                                               read_fw_status_reg(
+                                                       instance->reg_set);
+                                       abs_state = status_reg &
+                                               MFI_STATE_MASK;
+                                       if (abs_state == MFI_STATE_READY) {
+                                               printk(KERN_WARNING "megasas"
+                                                      ": SR-IOV: FW was found"
+                                                      "to be in ready state "
+                                                      "for scsi%d.\n",
+                                                      instance->host->host_no);
+                                               break;
+                                       }
+                                       msleep(20);
+                               }
+                               if (abs_state != MFI_STATE_READY) {
+                                       printk(KERN_WARNING "megasas: SR-IOV: "
+                                              "FW not in ready state after %d"
+                                              " seconds for scsi%d, status_reg = "
+                                              "0x%x.\n",
+                                              MEGASAS_RESET_WAIT_TIME,
+                                              instance->host->host_no,
+                                              status_reg);
+                                       megaraid_sas_kill_hba(instance);
+                                       instance->skip_heartbeat_timer_del = 1;
+                                       instance->adprecovery =
+                                               MEGASAS_HW_CRITICAL_ERROR;
+                                       retval = FAILED;
+                                       goto out;
+                               }
+                       }
+               }
+
                /* Now try to reset the chip */
                for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
                        writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
                                readl(&instance->reg_set->fusion_host_diag);
                                if (retry++ == 100) {
                                        printk(KERN_WARNING "megaraid_sas: "
-                                              "Host diag unlock failed!\n");
+                                              "Host diag unlock failed! "
+                                              "for scsi%d\n",
+                                               instance->host->host_no);
                                        break;
                                }
                        }
                                if (retry++ == 1000) {
                                        printk(KERN_WARNING "megaraid_sas: "
                                               "Diag reset adapter never "
-                                              "cleared!\n");
+                                              "cleared for scsi%d!\n",
+                                               instance->host->host_no);
                                        break;
                                }
                        }
                        if (abs_state <= MFI_STATE_FW_INIT) {
                                printk(KERN_WARNING "megaraid_sas: firmware "
                                       "state < MFI_STATE_FW_INIT, state = "
-                                      "0x%x\n", abs_state);
+                                      "0x%x for scsi%d\n", abs_state,
+                                       instance->host->host_no);
                                continue;
                        }
 
                        /* Wait for FW to become ready */
                        if (megasas_transition_to_ready(instance, 1)) {
                                printk(KERN_WARNING "megaraid_sas: Failed to "
-                                      "transition controller to ready.\n");
+                                      "transition controller to ready "
+                                      "for scsi%d.\n",
+                                      instance->host->host_no);
                                continue;
                        }
 
                        megasas_reset_reply_desc(instance);
                        if (megasas_ioc_init_fusion(instance)) {
                                printk(KERN_WARNING "megaraid_sas: "
-                                      "megasas_ioc_init_fusion() failed!\n");
+                                      "megasas_ioc_init_fusion() failed!"
+                                      " for scsi%d\n",
+                                      instance->host->host_no);
                                continue;
                        }
 
-                       clear_bit(MEGASAS_FUSION_IN_RESET,
-                                 &instance->reset_flags);
-                       instance->instancet->enable_intr(instance);
-                       instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
-
                        /* Re-fire management commands */
                        for (j = 0 ; j < instance->max_fw_cmds; j++) {
                                cmd_fusion = fusion->cmd_list[j];
                                                if (!req_desc) {
                                                        printk(KERN_WARNING
                                                               "req_desc NULL"
-                                                              "\n");
+                                                              " for scsi%d\n",
+                                                               instance->host->host_no);
                                                        /* Return leaked MPT
                                                           frame */
                                                        megasas_return_cmd_fusion(instance, cmd_fusion);
                                }
                        }
 
+                       clear_bit(MEGASAS_FUSION_IN_RESET,
+                                 &instance->reset_flags);
+                       instance->instancet->enable_intr(instance);
+                       instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+
                        /* Reset load balance info */
                        memset(fusion->load_balance_info, 0,
                               sizeof(struct LD_LOAD_BALANCE_INFO)
                        if (!megasas_get_map_info(instance))
                                megasas_sync_map_info(instance);
 
+                       /* Restart SR-IOV heartbeat */
+                       if (instance->requestorId) {
+                               if (!megasas_sriov_start_heartbeat(instance, 0))
+                                       megasas_start_timer(instance,
+                                                           &instance->sriov_heartbeat_timer,
+                                                           megasas_sriov_heartbeat_handler,
+                                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+                               else
+                                       instance->skip_heartbeat_timer_del = 1;
+                       }
+
                        /* Adapter reset completed successfully */
                        printk(KERN_WARNING "megaraid_sas: Reset "
-                              "successful.\n");
+                              "successful for scsi%d.\n",
+                               instance->host->host_no);
                        retval = SUCCESS;
                        goto out;
                }
                /* Reset failed, kill the adapter */
                printk(KERN_WARNING "megaraid_sas: Reset failed, killing "
-                      "adapter.\n");
+                      "adapter scsi%d.\n", instance->host->host_no);
                megaraid_sas_kill_hba(instance);
+               instance->skip_heartbeat_timer_del = 1;
                instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
                retval = FAILED;
        } else {
+               /* For VF: Restart HB timer if we didn't OCR */
+               if (instance->requestorId) {
+                       megasas_start_timer(instance,
+                                           &instance->sriov_heartbeat_timer,
+                                           megasas_sriov_heartbeat_handler,
+                                           MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF);
+               }
                clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
                instance->instancet->enable_intr(instance);
                instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
        struct megasas_instance *instance =
                container_of(work, struct megasas_instance, work_init);
 
-       megasas_reset_fusion(instance->host);
+       megasas_reset_fusion(instance->host, 0);
 }
 
 struct megasas_instance_template megasas_instance_template_fusion = {