]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/scsi/megaraid/megaraid_sas_fusion.c
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux.git] / drivers / scsi / megaraid / megaraid_sas_fusion.c
index dba4de04de3cf4fb6206db4235944f82367184a6..46a0f8f4f677eeeac6ad18e28cf3810e1554165d 100644 (file)
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_dbg.h>
+#include <linux/dmi.h>
 
 #include "megaraid_sas_fusion.h"
 #include "megaraid_sas.h"
 
+
 extern void megasas_free_cmds(struct megasas_instance *instance);
 extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance
                                           *instance);
@@ -156,28 +158,15 @@ megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs)
  * megasas_get_cmd_fusion -    Get a command from the free pool
  * @instance:          Adapter soft state
  *
- * Returns a free command from the pool
+ * Returns a blk_tag indexed mpt frame
  */
-struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance
-                                                 *instance)
+inline struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance
+                                                 *instance, u32 blk_tag)
 {
-       unsigned long flags;
-       struct fusion_context *fusion =
-               (struct fusion_context *)instance->ctrl_context;
-       struct megasas_cmd_fusion *cmd = NULL;
-
-       spin_lock_irqsave(&fusion->mpt_pool_lock, flags);
-
-       if (!list_empty(&fusion->cmd_pool)) {
-               cmd = list_entry((&fusion->cmd_pool)->next,
-                                struct megasas_cmd_fusion, list);
-               list_del_init(&cmd->list);
-       } else {
-               printk(KERN_ERR "megasas: Command pool (fusion) empty!\n");
-       }
+       struct fusion_context *fusion;
 
-       spin_unlock_irqrestore(&fusion->mpt_pool_lock, flags);
-       return cmd;
+       fusion = instance->ctrl_context;
+       return fusion->cmd_list[blk_tag];
 }
 
 /**
@@ -188,47 +177,35 @@ struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance
 inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
        struct megasas_cmd_fusion *cmd)
 {
-       unsigned long flags;
-       struct fusion_context *fusion =
-               (struct fusion_context *)instance->ctrl_context;
-
-       spin_lock_irqsave(&fusion->mpt_pool_lock, flags);
-
        cmd->scmd = NULL;
-       cmd->sync_cmd_idx = (u32)ULONG_MAX;
        memset(cmd->io_request, 0, sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
-       list_add(&cmd->list, (&fusion->cmd_pool)->next);
-
-       spin_unlock_irqrestore(&fusion->mpt_pool_lock, flags);
 }
 
 /**
- * megasas_return_mfi_mpt_pthr - Return a mfi and mpt to free command pool
- * @instance:          Adapter soft state
- * @cmd_mfi:           MFI Command packet to be returned to free command pool
- * @cmd_mpt:           MPT Command packet to be returned to free command pool
+ * megasas_fire_cmd_fusion -   Sends command to the FW
  */
-inline void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
-               struct megasas_cmd *cmd_mfi,
-               struct megasas_cmd_fusion *cmd_fusion)
+static void
+megasas_fire_cmd_fusion(struct megasas_instance *instance,
+               union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
 {
+#if defined(writeq) && defined(CONFIG_64BIT)
+       u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
+                       le32_to_cpu(req_desc->u.low));
+
+       writeq(req_data, &instance->reg_set->inbound_low_queue_port);
+#else
        unsigned long flags;
 
-       /*
-        * TO DO: optimize this code and use only one lock instead of two
-        * locks being used currently- mpt_pool_lock is acquired
-        * inside mfi_pool_lock
-        */
-       spin_lock_irqsave(&instance->mfi_pool_lock, flags);
-       megasas_return_cmd_fusion(instance, cmd_fusion);
-       if (atomic_read(&cmd_mfi->mfi_mpt_pthr) != MFI_MPT_ATTACHED)
-               dev_err(&instance->pdev->dev, "Possible bug from %s %d\n",
-                       __func__, __LINE__);
-       atomic_set(&cmd_mfi->mfi_mpt_pthr, MFI_MPT_DETACHED);
-       __megasas_return_cmd(instance, cmd_mfi);
-       spin_unlock_irqrestore(&instance->mfi_pool_lock, flags);
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       writel(le32_to_cpu(req_desc->u.low),
+               &instance->reg_set->inbound_low_queue_port);
+       writel(le32_to_cpu(req_desc->u.high),
+               &instance->reg_set->inbound_high_queue_port);
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
+#endif
 }
 
+
 /**
  * megasas_teardown_frame_pool_fusion -        Destroy the cmd frame DMA pool
  * @instance:                          Adapter soft state
@@ -326,7 +303,6 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
        kfree(fusion->cmd_list);
        fusion->cmd_list = NULL;
 
-       INIT_LIST_HEAD(&fusion->cmd_pool);
 }
 
 /**
@@ -464,7 +440,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
 
        reply_desc = fusion->reply_frames_desc;
        for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
-               reply_desc->Words = ULLONG_MAX;
+               reply_desc->Words = cpu_to_le64(ULLONG_MAX);
 
        io_frames_sz = fusion->io_frames_alloc_sz;
 
@@ -535,7 +511,9 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
                memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
                cmd->index = i + 1;
                cmd->scmd = NULL;
-               cmd->sync_cmd_idx = (u32)ULONG_MAX; /* Set to Invalid */
+               cmd->sync_cmd_idx = (i >= instance->max_scsi_cmds) ?
+                               (i - instance->max_scsi_cmds) :
+                               (u32)ULONG_MAX; /* Set to Invalid */
                cmd->instance = instance;
                cmd->io_request =
                        (struct MPI2_RAID_SCSI_IO_REQUEST *)
@@ -543,8 +521,6 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
                memset(cmd->io_request, 0,
                       sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
                cmd->io_request_phys_addr = io_req_base_phys + offset;
-
-               list_add_tail(&cmd->list, &fusion->cmd_pool);
        }
 
        /*
@@ -605,14 +581,11 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
                msleep(20);
        }
 
-       if (frame_hdr->cmd_status == 0xff) {
-               if (fusion)
-                       megasas_return_mfi_mpt_pthr(instance, cmd,
-                               cmd->mpt_pthr_cmd_blocked);
+       if (frame_hdr->cmd_status == 0xff)
                return -ETIME;
-       }
 
-       return 0;
+       return (frame_hdr->cmd_status == MFI_STAT_OK) ?
+               0 : 1;
 }
 
 /**
@@ -633,6 +606,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
        union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
        int i;
        struct megasas_header *frame_hdr;
+       const char *sys_info;
 
        fusion = instance->ctrl_context;
 
@@ -673,7 +647,9 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
 
        frame_hdr = &cmd->frame->hdr;
        frame_hdr->cmd_status = 0xFF;
-       frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
+       frame_hdr->flags = cpu_to_le16(
+               le16_to_cpu(frame_hdr->flags) |
+               MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
 
        init_frame->cmd = MFI_CMD_INIT;
        init_frame->cmd_status = 0xFF;
@@ -695,6 +671,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
        /* Convert capability to LE32 */
        cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
 
+       sys_info = dmi_get_system_info(DMI_PRODUCT_UUID);
+       if (instance->system_info_buf && sys_info) {
+               memcpy(instance->system_info_buf->systemId, sys_info,
+                       strlen(sys_info) > 64 ? 64 : strlen(sys_info));
+               instance->system_info_buf->systemIdLength =
+                       strlen(sys_info) > 64 ? 64 : strlen(sys_info);
+               init_frame->system_info_lo = instance->system_info_h;
+               init_frame->system_info_hi = 0;
+       }
+
        init_frame->queue_info_new_phys_addr_hi =
                cpu_to_le32(upper_32_bits(ioc_init_handle));
        init_frame->queue_info_new_phys_addr_lo =
@@ -719,8 +705,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                        break;
        }
 
-       instance->instancet->fire_cmd(instance, req_desc.u.low,
-                                     req_desc.u.high, instance->reg_set);
+       megasas_fire_cmd_fusion(instance, &req_desc);
 
        wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS);
 
@@ -820,11 +805,7 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
        else
                ret = megasas_issue_polled(instance, cmd);
 
-       if (instance->ctrl_context && cmd->mpt_pthr_cmd_blocked)
-               megasas_return_mfi_mpt_pthr(instance, cmd,
-                       cmd->mpt_pthr_cmd_blocked);
-       else
-               megasas_return_cmd(instance, cmd);
+       megasas_return_cmd(instance, cmd);
 
        return ret;
 }
@@ -1060,6 +1041,15 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        for (i = 0 ; i < count; i++)
                fusion->last_reply_idx[i] = 0;
 
+       /*
+        * For fusion adapters, 3 commands for IOCTL and 5 commands
+        * for driver's internal DCMDs.
+        */
+       instance->max_scsi_cmds = instance->max_fw_cmds -
+                               (MEGASAS_FUSION_INTERNAL_CMDS +
+                               MEGASAS_FUSION_IOCTL_CMDS);
+       sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS);
+
        /*
         * Allocate memory for descriptors
         * Create a pool of commands
@@ -1130,34 +1120,6 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        return 1;
 }
 
-/**
- * megasas_fire_cmd_fusion -   Sends command to the FW
- * @frame_phys_addr :          Physical address of cmd
- * @frame_count :              Number of frames for the command
- * @regs :                     MFI register set
- */
-void
-megasas_fire_cmd_fusion(struct megasas_instance *instance,
-                       dma_addr_t req_desc_lo,
-                       u32 req_desc_hi,
-                       struct megasas_register_set __iomem *regs)
-{
-#if defined(writeq) && defined(CONFIG_64BIT)
-       u64 req_data = (((u64)le32_to_cpu(req_desc_hi) << 32) |
-                       le32_to_cpu(req_desc_lo));
-
-       writeq(req_data, &(regs)->inbound_low_queue_port);
-#else
-       unsigned long flags;
-
-       spin_lock_irqsave(&instance->hba_lock, flags);
-
-       writel(le32_to_cpu(req_desc_lo), &(regs)->inbound_low_queue_port);
-       writel(le32_to_cpu(req_desc_hi), &(regs)->inbound_high_queue_port);
-       spin_unlock_irqrestore(&instance->hba_lock, flags);
-#endif
-}
-
 /**
  * map_cmd_status -    Maps FW cmd status to OS cmd status
  * @cmd :              Pointer to cmd
@@ -1497,7 +1459,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
        u8 *raidLUN;
 
-       device_id = MEGASAS_DEV_INDEX(instance, scp);
+       device_id = MEGASAS_DEV_INDEX(scp);
 
        fusion = instance->ctrl_context;
 
@@ -1621,6 +1583,14 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                        cmd->pd_r1_lb = io_info.pd_after_lb;
                } else
                        scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
+
+               if ((raidLUN[0] == 1) &&
+                       (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 2)) {
+                       instance->dev_handle = !(instance->dev_handle);
+                       io_info.devHandle =
+                               local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].devHandle[instance->dev_handle];
+               }
+
                cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
                io_request->DevHandle = io_info.devHandle;
                /* populate the LUN field */
@@ -1650,121 +1620,68 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
 }
 
 /**
- * megasas_build_dcdb_fusion - Prepares IOs to devices
+ * megasas_build_ld_nonrw_fusion - prepares non rw ios for virtual disk
  * @instance:          Adapter soft state
  * @scp:               SCSI command
  * @cmd:               Command to be prepared
  *
- * Prepares the io_request frame for non-io cmds
+ * Prepares the io_request frame for non-rw io cmds for vd.
  */
-static void
-megasas_build_dcdb_fusion(struct megasas_instance *instance,
-                         struct scsi_cmnd *scmd,
-                         struct megasas_cmd_fusion *cmd)
+static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
+                         struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd)
 {
        u32 device_id;
        struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
        u16 pd_index = 0;
-       u16 os_timeout_value;
-       u16 timeout_limit;
        struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
        struct fusion_context *fusion = instance->ctrl_context;
        u8                          span, physArm;
-       u16                         devHandle;
+       __le16                      devHandle;
        u32                         ld, arRef, pd;
        struct MR_LD_RAID                  *raid;
        struct RAID_CONTEXT                *pRAID_Context;
+       u8 fp_possible = 1;
 
        io_request = cmd->io_request;
-       device_id = MEGASAS_DEV_INDEX(instance, scmd);
-       pd_index = (scmd->device->channel * MEGASAS_MAX_DEV_PER_CHANNEL)
-               +scmd->device->id;
+       device_id = MEGASAS_DEV_INDEX(scmd);
+       pd_index = MEGASAS_PD_INDEX(scmd);
        local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
-
        io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
+       /* get RAID_Context pointer */
+       pRAID_Context = &io_request->RaidContext;
+       /* Check with FW team */
+       pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+       pRAID_Context->regLockRowLBA    = 0;
+       pRAID_Context->regLockLength    = 0;
 
-       if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS &&
-           instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
-               if (fusion->fast_path_io)
-                       io_request->DevHandle =
-                       local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
-               io_request->RaidContext.RAIDFlags =
-                       MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
-                       << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
-               cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
-               cmd->request_desc->SCSIIO.MSIxIndex =
-                       instance->msix_vectors ?
-                               raw_smp_processor_id() %
-                                       instance->msix_vectors :
-                               0;
-               os_timeout_value = scmd->request->timeout / HZ;
-
-               if (instance->secure_jbod_support &&
-                       (megasas_cmd_type(scmd) == NON_READ_WRITE_SYSPDIO)) {
-                       /* system pd firmware path */
-                       io_request->Function  =
-                               MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
-                       cmd->request_desc->SCSIIO.RequestFlags =
-                               (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
-                               MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
-                       io_request->RaidContext.timeoutValue =
-                               cpu_to_le16(os_timeout_value);
-               } else {
-                       /* system pd Fast Path */
-                       io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
-                       io_request->RaidContext.regLockFlags = 0;
-                       io_request->RaidContext.regLockRowLBA = 0;
-                       io_request->RaidContext.regLockLength = 0;
-                       timeout_limit = (scmd->device->type == TYPE_DISK) ?
-                                       255 : 0xFFFF;
-                       io_request->RaidContext.timeoutValue =
-                               cpu_to_le16((os_timeout_value > timeout_limit) ?
-                               timeout_limit : os_timeout_value);
-               if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
-                       (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
-                       io_request->IoFlags |=
-                       cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
-
-                       cmd->request_desc->SCSIIO.RequestFlags =
-                               (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
-                               MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
-               }
-       } else {
-               if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS)
-                       goto NonFastPath;
-
-               /*
-                * For older firmware, Driver should not access ldTgtIdToLd
-                * beyond index 127 and for Extended VD firmware, ldTgtIdToLd
-                * should not go beyond 255.
-                */
-
-               if ((!fusion->fast_path_io) ||
-                       (device_id >= instance->fw_supported_vd_count))
-                       goto NonFastPath;
+       if (fusion->fast_path_io && (
+               device_id < instance->fw_supported_vd_count)) {
 
                ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
-
                if (ld >= instance->fw_supported_vd_count)
-                       goto NonFastPath;
+                       fp_possible = 0;
 
                raid = MR_LdRaidGet(ld, local_map_ptr);
-
-               /* check if this LD is FP capable */
                if (!(raid->capability.fpNonRWCapable))
-                       /* not FP capable, send as non-FP */
-                       goto NonFastPath;
+                       fp_possible = 0;
+       } else
+               fp_possible = 0;
 
-               /* get RAID_Context pointer */
-               pRAID_Context = &io_request->RaidContext;
+       if (!fp_possible) {
+               io_request->Function  = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+               io_request->DevHandle = cpu_to_le16(device_id);
+               io_request->LUN[1] = scmd->device->lun;
+               pRAID_Context->timeoutValue =
+                       cpu_to_le16 (scmd->request->timeout / HZ);
+               cmd->request_desc->SCSIIO.RequestFlags =
+                       (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
+                       MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+       } else {
 
                /* set RAID context values */
-               pRAID_Context->regLockFlags     = REGION_TYPE_SHARED_READ;
-               pRAID_Context->timeoutValue     = cpu_to_le16(raid->fpIoTimeoutForLd);
-               pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
-               pRAID_Context->regLockRowLBA    = 0;
-               pRAID_Context->regLockLength    = 0;
-               pRAID_Context->configSeqNum     = raid->seqNum;
+               pRAID_Context->configSeqNum = raid->seqNum;
+               pRAID_Context->regLockFlags = REGION_TYPE_SHARED_READ;
+               pRAID_Context->timeoutValue = cpu_to_le16(raid->fpIoTimeoutForLd);
 
                /* get the DevHandle for the PD (since this is
                   fpNonRWCapable, this is a single disk RAID0) */
@@ -1776,7 +1693,7 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
                /* build request descriptor */
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
-                        MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+                       MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
                cmd->request_desc->SCSIIO.DevHandle = devHandle;
 
                /* populate the LUN field */
@@ -1785,18 +1702,87 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
                /* build the raidScsiIO structure */
                io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
                io_request->DevHandle = devHandle;
+       }
+}
 
-               return;
+/**
+ * megasas_build_syspd_fusion - prepares rw/non-rw ios for syspd
+ * @instance:          Adapter soft state
+ * @scp:               SCSI command
+ * @cmd:               Command to be prepared
+ * @fp_possible:       parameter to detect fast path or firmware path io.
+ *
+ * Prepares the io_request frame for rw/non-rw io cmds for syspds
+ */
+static void
+megasas_build_syspd_fusion(struct megasas_instance *instance,
+       struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd, u8 fp_possible)
+{
+       u32 device_id;
+       struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
+       u16 pd_index = 0;
+       u16 os_timeout_value;
+       u16 timeout_limit;
+       struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
+       struct RAID_CONTEXT     *pRAID_Context;
+       struct fusion_context *fusion = instance->ctrl_context;
+
+       device_id = MEGASAS_DEV_INDEX(scmd);
+       pd_index = MEGASAS_PD_INDEX(scmd);
+       os_timeout_value = scmd->request->timeout / HZ;
 
-NonFastPath:
+       io_request = cmd->io_request;
+       /* get RAID_Context pointer */
+       pRAID_Context = &io_request->RaidContext;
+       io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
+       io_request->LUN[1] = scmd->device->lun;
+       pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
+               << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
+
+       pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+       pRAID_Context->configSeqNum = 0;
+       local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
+       io_request->DevHandle =
+               local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+
+       cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
+       cmd->request_desc->SCSIIO.MSIxIndex =
+               instance->msix_vectors ?
+               (raw_smp_processor_id() % instance->msix_vectors) : 0;
+
+
+       if (!fp_possible) {
+               /* system pd firmware path */
                io_request->Function  = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
-               io_request->DevHandle = cpu_to_le16(device_id);
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
-                        MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+                               MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+               pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value);
+       } else {
+               /* system pd Fast Path */
+               io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+               pRAID_Context->regLockFlags = 0;
+               pRAID_Context->regLockRowLBA = 0;
+               pRAID_Context->regLockLength = 0;
+               timeout_limit = (scmd->device->type == TYPE_DISK) ?
+                               255 : 0xFFFF;
+               pRAID_Context->timeoutValue =
+                       cpu_to_le16((os_timeout_value > timeout_limit) ?
+                       timeout_limit : os_timeout_value);
+               if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
+                       (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+                       cmd->request_desc->SCSIIO.RequestFlags |=
+                               (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
+                               MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+                       pRAID_Context->Type = MPI2_TYPE_CUDA;
+                       pRAID_Context->nseg = 0x1;
+                       io_request->IoFlags |=
+                               cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
+               }
+               cmd->request_desc->SCSIIO.RequestFlags =
+                       (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+                               MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
        }
-       io_request->RaidContext.VirtualDiskTgtId = cpu_to_le16(device_id);
-       int_to_scsilun(scmd->device->lun, (struct scsi_lun *)io_request->LUN);
 }
 
 /**
@@ -1813,11 +1799,10 @@ megasas_build_io_fusion(struct megasas_instance *instance,
                        struct scsi_cmnd *scp,
                        struct megasas_cmd_fusion *cmd)
 {
-       u32 device_id, sge_count;
+       u32 sge_count;
+       u8  cmd_type;
        struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
 
-       device_id = MEGASAS_DEV_INDEX(instance, scp);
-
        /* Zero out some fields so they don't get reused */
        memset(io_request->LUN, 0x0, 8);
        io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
@@ -1837,10 +1822,24 @@ megasas_build_io_fusion(struct megasas_instance *instance,
         */
        io_request->IoFlags = cpu_to_le16(scp->cmd_len);
 
-       if (megasas_cmd_type(scp) == READ_WRITE_LDIO)
+       switch (cmd_type = megasas_cmd_type(scp)) {
+       case READ_WRITE_LDIO:
                megasas_build_ldio_fusion(instance, scp, cmd);
-       else
-               megasas_build_dcdb_fusion(instance, scp, cmd);
+               break;
+       case NON_READ_WRITE_LDIO:
+               megasas_build_ld_nonrw_fusion(instance, scp, cmd);
+               break;
+       case READ_WRITE_SYSPDIO:
+       case NON_READ_WRITE_SYSPDIO:
+               if (instance->secure_jbod_support &&
+                       (cmd_type == NON_READ_WRITE_SYSPDIO))
+                       megasas_build_syspd_fusion(instance, scp, cmd, 0);
+               else
+                       megasas_build_syspd_fusion(instance, scp, cmd, 1);
+               break;
+       default:
+               break;
+       }
 
        /*
         * Construct SGL
@@ -1915,9 +1914,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
 
        fusion = instance->ctrl_context;
 
-       cmd = megasas_get_cmd_fusion(instance);
-       if (!cmd)
-               return SCSI_MLQUEUE_HOST_BUSY;
+       cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
 
        index = cmd->index;
 
@@ -1948,9 +1945,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
         */
        atomic_inc(&instance->fw_outstanding);
 
-       instance->instancet->fire_cmd(instance,
-                                     req_desc->u.low, req_desc->u.high,
-                                     instance->reg_set);
+       megasas_fire_cmd_fusion(instance, req_desc);
 
        return 0;
 }
@@ -1975,6 +1970,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
        union desc_value d_val;
        struct LD_LOAD_BALANCE_INFO *lbinfo;
        int threshold_reply_count = 0;
+       struct scsi_cmnd *scmd_local = NULL;
 
        fusion = instance->ctrl_context;
 
@@ -1998,7 +1994,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 
        num_completed = 0;
 
-       while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) {
+       while (d_val.u.low != cpu_to_le32(UINT_MAX) &&
+              d_val.u.high != cpu_to_le32(UINT_MAX)) {
                smid = le16_to_cpu(reply_desc->SMID);
 
                cmd_fusion = fusion->cmd_list[smid - 1];
@@ -2010,14 +2007,14 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                if (cmd_fusion->scmd)
                        cmd_fusion->scmd->SCp.ptr = NULL;
 
+               scmd_local = cmd_fusion->scmd;
                status = scsi_io_req->RaidContext.status;
                extStatus = scsi_io_req->RaidContext.exStatus;
 
                switch (scsi_io_req->Function) {
                case MPI2_FUNCTION_SCSI_IO_REQUEST:  /*Fast Path IO.*/
                        /* Update load balancing info */
-                       device_id = MEGASAS_DEV_INDEX(instance,
-                                                     cmd_fusion->scmd);
+                       device_id = MEGASAS_DEV_INDEX(scmd_local);
                        lbinfo = &fusion->load_balance_info[device_id];
                        if (cmd_fusion->scmd->SCp.Status &
                            MEGASAS_LOAD_BALANCE_FLAG) {
@@ -2035,29 +2032,25 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
                        /* Map the FW Cmd Status */
                        map_cmd_status(cmd_fusion, status, extStatus);
-                       scsi_dma_unmap(cmd_fusion->scmd);
-                       cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
                        scsi_io_req->RaidContext.status = 0;
                        scsi_io_req->RaidContext.exStatus = 0;
                        megasas_return_cmd_fusion(instance, cmd_fusion);
+                       scsi_dma_unmap(scmd_local);
+                       scmd_local->scsi_done(scmd_local);
                        atomic_dec(&instance->fw_outstanding);
 
                        break;
                case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */
                        cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
 
-                       if (!cmd_mfi->mpt_pthr_cmd_blocked) {
-                               if (megasas_dbg_lvl == 5)
-                                       dev_info(&instance->pdev->dev,
-                                               "freeing mfi/mpt pass-through "
-                                               "from %s %d\n",
-                                                __func__, __LINE__);
-                               megasas_return_mfi_mpt_pthr(instance, cmd_mfi,
-                                       cmd_fusion);
-                       }
-
-                       megasas_complete_cmd(instance, cmd_mfi, DID_OK);
-                       cmd_fusion->flags = 0;
+                       /* Poll mode. Dummy free.
+                        * In case of Interrupt mode, caller has reverse check.
+                        */
+                       if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) {
+                               cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE;
+                               megasas_return_cmd(instance, cmd_mfi);
+                       } else
+                               megasas_complete_cmd(instance, cmd_mfi, DID_OK);
                        break;
                }
 
@@ -2066,7 +2059,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                    fusion->reply_q_depth)
                        fusion->last_reply_idx[MSIxIndex] = 0;
 
-               desc->Words = ULLONG_MAX;
+               desc->Words = cpu_to_le64(ULLONG_MAX);
                num_completed++;
                threshold_reply_count++;
 
@@ -2217,27 +2210,14 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
        struct megasas_cmd_fusion *cmd;
        struct fusion_context *fusion;
        struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr;
-       u32 opcode;
 
-       cmd = megasas_get_cmd_fusion(instance);
-       if (!cmd)
-               return 1;
+       fusion = instance->ctrl_context;
+
+       cmd = megasas_get_cmd_fusion(instance,
+                       instance->max_scsi_cmds + mfi_cmd->index);
 
        /*  Save the smid. To be used for returning the cmd */
        mfi_cmd->context.smid = cmd->index;
-       cmd->sync_cmd_idx = mfi_cmd->index;
-
-       /* Set this only for Blocked commands */
-       opcode = le32_to_cpu(mfi_cmd->frame->dcmd.opcode);
-       if ((opcode == MR_DCMD_LD_MAP_GET_INFO)
-               && (mfi_cmd->frame->dcmd.mbox.b[1] == 1))
-               mfi_cmd->is_wait_event = 1;
-
-       if (opcode == MR_DCMD_CTRL_EVENT_WAIT)
-               mfi_cmd->is_wait_event = 1;
-
-       if (mfi_cmd->is_wait_event)
-               mfi_cmd->mpt_pthr_cmd_blocked = cmd;
 
        /*
         * For cmds where the flag is set, store the flag and check
@@ -2246,9 +2226,8 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
         */
 
        if (frame_hdr->flags & cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE))
-               cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+               mfi_cmd->flags |= DRV_DCMD_POLLED_MODE;
 
-       fusion = instance->ctrl_context;
        io_req = cmd->io_request;
 
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
@@ -2327,9 +2306,7 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance,
                printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n");
                return;
        }
-       atomic_set(&cmd->mfi_mpt_pthr, MFI_MPT_ATTACHED);
-       instance->instancet->fire_cmd(instance, req_desc->u.low,
-                                     req_desc->u.high, instance->reg_set);
+       megasas_fire_cmd_fusion(instance, req_desc);
 }
 
 /**
@@ -2508,7 +2485,42 @@ void  megasas_reset_reply_desc(struct megasas_instance *instance)
                fusion->last_reply_idx[i] = 0;
        reply_desc = fusion->reply_frames_desc;
        for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
-               reply_desc->Words = ULLONG_MAX;
+               reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+}
+
+/*
+ * megasas_refire_mgmt_cmd :   Re-fire management commands
+ * @instance:                          Controller's soft instance
+*/
+void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
+{
+       int j;
+       struct megasas_cmd_fusion *cmd_fusion;
+       struct fusion_context *fusion;
+       struct megasas_cmd *cmd_mfi;
+       union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+       u16 smid;
+
+       fusion = instance->ctrl_context;
+
+       /* Re-fire management commands.
+        * Do not traverse complet MPT frame pool. Start from max_scsi_cmds.
+        */
+       for (j = instance->max_scsi_cmds ; j < instance->max_fw_cmds; j++) {
+               cmd_fusion = fusion->cmd_list[j];
+               cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
+               smid = le16_to_cpu(cmd_mfi->context.smid);
+
+               if (!smid)
+                       continue;
+               req_desc = megasas_get_request_descriptor
+                                       (instance, smid - 1);
+               if (req_desc && (cmd_mfi->frame->dcmd.opcode !=
+                               cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)))
+                       megasas_fire_cmd_fusion(instance, req_desc);
+               else
+                       megasas_return_cmd(instance, cmd_mfi);
+       }
 }
 
 /* Check for a second path that is currently UP */
@@ -2538,14 +2550,13 @@ int megasas_check_mpio_paths(struct megasas_instance *instance,
 /* Core fusion reset function */
 int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
 {
-       int retval = SUCCESS, i, j, retry = 0, convert = 0;
+       int retval = SUCCESS, i, retry = 0, convert = 0;
        struct megasas_instance *instance;
        struct megasas_cmd_fusion *cmd_fusion;
        struct fusion_context *fusion;
-       struct megasas_cmd *cmd_mfi;
-       union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
        u32 host_diag, abs_state, status_reg, reset_adapter;
        u32 io_timeout_in_crash_mode = 0;
+       struct scsi_cmnd *scmd_local = NULL;
 
        instance = (struct megasas_instance *)shost->hostdata;
        fusion = instance->ctrl_context;
@@ -2613,15 +2624,16 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
                        iotimeout = 0;
 
                /* Now return commands back to the OS */
-               for (i = 0 ; i < instance->max_fw_cmds; i++) {
+               for (i = 0 ; i < instance->max_scsi_cmds; i++) {
                        cmd_fusion = fusion->cmd_list[i];
+                       scmd_local = cmd_fusion->scmd;
                        if (cmd_fusion->scmd) {
-                               scsi_dma_unmap(cmd_fusion->scmd);
-                               cmd_fusion->scmd->result =
+                               scmd_local->result =
                                        megasas_check_mpio_paths(instance,
-                                                                cmd_fusion->scmd);
-                               cmd_fusion->scmd->scsi_done(cmd_fusion->scmd);
+                                                       scmd_local);
                                megasas_return_cmd_fusion(instance, cmd_fusion);
+                               scsi_dma_unmap(scmd_local);
+                               scmd_local->scsi_done(scmd_local);
                                atomic_dec(&instance->fw_outstanding);
                        }
                }
@@ -2790,44 +2802,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
                                continue;
                        }
 
-                       /* Re-fire management commands */
-                       for (j = 0 ; j < instance->max_fw_cmds; j++) {
-                               cmd_fusion = fusion->cmd_list[j];
-                               if (cmd_fusion->sync_cmd_idx !=
-                                   (u32)ULONG_MAX) {
-                                       cmd_mfi =
-                                       instance->
-                                       cmd_list[cmd_fusion->sync_cmd_idx];
-                                       if (cmd_mfi->frame->dcmd.opcode ==
-                                           cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) {
-                                               megasas_return_mfi_mpt_pthr(instance, cmd_mfi, cmd_fusion);
-                                       } else  {
-                                               req_desc =
-                                               megasas_get_request_descriptor(
-                                                       instance,
-                                                       cmd_mfi->context.smid
-                                                       -1);
-                                               if (!req_desc) {
-                                                       printk(KERN_WARNING
-                                                              "req_desc NULL"
-                                                              " for scsi%d\n",
-                                                               instance->host->host_no);
-                                                       /* Return leaked MPT
-                                                          frame */
-                                                       megasas_return_cmd_fusion(instance, cmd_fusion);
-                                               } else {
-                                                       instance->instancet->
-                                                       fire_cmd(instance,
-                                                                req_desc->
-                                                                u.low,
-                                                                req_desc->
-                                                                u.high,
-                                                                instance->
-                                                                reg_set);
-                                               }
-                                       }
-                               }
-                       }
+                       megasas_refire_mgmt_cmd(instance);
 
                        if (megasas_get_ctrl_info(instance)) {
                                dev_info(&instance->pdev->dev,
@@ -2978,7 +2953,6 @@ void megasas_fusion_ocr_wq(struct work_struct *work)
 }
 
 struct megasas_instance_template megasas_instance_template_fusion = {
-       .fire_cmd = megasas_fire_cmd_fusion,
        .enable_intr = megasas_enable_intr_fusion,
        .disable_intr = megasas_disable_intr_fusion,
        .clear_intr = megasas_clear_intr_fusion,