Merge branch 'stable/vmalloc-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / scsi / megaraid / megaraid_sas_fusion.c
index f13e7ab..bfd87fa 100644 (file)
@@ -74,7 +74,8 @@ megasas_issue_polled(struct megasas_instance *instance,
                     struct megasas_cmd *cmd);
 
 u8
-MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info,
+MR_BuildRaidContext(struct megasas_instance *instance,
+                   struct IO_REQUEST_INFO *io_info,
                    struct RAID_CONTEXT *pRAID_Context,
                    struct MR_FW_RAID_MAP_ALL *map);
 u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
@@ -89,7 +90,7 @@ u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
                      struct LD_LOAD_BALANCE_INFO *lbInfo);
 u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
                           struct IO_REQUEST_INFO *in_info);
-int megasas_transition_to_ready(struct megasas_instance *instance);
+int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
 void megaraid_sas_kill_hba(struct megasas_instance *instance);
 
 extern u32 megasas_dbg_lvl;
@@ -101,6 +102,10 @@ extern u32 megasas_dbg_lvl;
 void
 megasas_enable_intr_fusion(struct megasas_register_set __iomem *regs)
 {
+       /* For Thunderbolt/Invader also clear intr on enable */
+       writel(~0, &regs->outbound_intr_status);
+       readl(&regs->outbound_intr_status);
+
        writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
 
        /* Dummy readl to force pci flush */
@@ -139,11 +144,6 @@ megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs)
        if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
                return 0;
 
-       /*
-        * dummy read to flush PCI
-        */
-       readl(&regs->outbound_intr_status);
-
        return 1;
 }
 
@@ -385,7 +385,7 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
 int
 megasas_alloc_cmds_fusion(struct megasas_instance *instance)
 {
-       int i, j;
+       int i, j, count;
        u32 max_cmd, io_frames_sz;
        struct fusion_context *fusion;
        struct megasas_cmd_fusion *cmd;
@@ -409,9 +409,10 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
                goto fail_req_desc;
        }
 
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
        fusion->reply_frames_desc_pool =
                pci_pool_create("reply_frames pool", instance->pdev,
-                               fusion->reply_alloc_sz, 16, 0);
+                               fusion->reply_alloc_sz * count, 16, 0);
 
        if (!fusion->reply_frames_desc_pool) {
                printk(KERN_ERR "megasas; Could not allocate memory for "
@@ -430,7 +431,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
        }
 
        reply_desc = fusion->reply_frames_desc;
-       for (i = 0; i < fusion->reply_q_depth; i++, reply_desc++)
+       for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
                reply_desc->Words = ULLONG_MAX;
 
        io_frames_sz = fusion->io_frames_alloc_sz;
@@ -590,7 +591,6 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
        struct megasas_init_frame *init_frame;
        struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
        dma_addr_t      ioc_init_handle;
-       u32 context;
        struct megasas_cmd *cmd;
        u8 ret;
        struct fusion_context *fusion;
@@ -634,14 +634,13 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                fusion->reply_frames_desc_phys;
        IOCInitMessage->SystemRequestFrameBaseAddress =
                fusion->io_request_frames_phys;
-
+       /* Set to 0 for none or 1 MSI-X vectors */
+       IOCInitMessage->HostMSIxVectors = (instance->msix_vectors > 0 ?
+                                          instance->msix_vectors : 0);
        init_frame = (struct megasas_init_frame *)cmd->frame;
        memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
 
        frame_hdr = &cmd->frame->hdr;
-       context = init_frame->context;
-       init_frame->context = context;
-
        frame_hdr->cmd_status = 0xFF;
        frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
 
@@ -881,7 +880,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        struct megasas_register_set __iomem *reg_set;
        struct fusion_context *fusion;
        u32 max_cmd;
-       int i = 0;
+       int i = 0, count;
 
        fusion = instance->ctrl_context;
 
@@ -933,7 +932,9 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
                (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
                 sizeof(union MPI2_SGE_IO_UNION))/16;
 
-       fusion->last_reply_idx = 0;
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+       for (i = 0 ; i < count; i++)
+               fusion->last_reply_idx[i] = 0;
 
        /*
         * Allocate memory for descriptors
@@ -1043,7 +1044,9 @@ map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
        case MFI_STAT_DEVICE_NOT_FOUND:
                cmd->scmd->result = DID_BAD_TARGET << 16;
                break;
-
+       case MFI_STAT_CONFIG_SEQ_MISMATCH:
+               cmd->scmd->result = DID_IMM_RETRY << 16;
+               break;
        default:
                printk(KERN_DEBUG "megasas: FW status %#x\n", status);
                cmd->scmd->result = DID_ERROR << 16;
@@ -1066,14 +1069,17 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                        struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
                        struct megasas_cmd_fusion *cmd)
 {
-       int i, sg_processed;
-       int sge_count, sge_idx;
+       int i, sg_processed, sge_count;
        struct scatterlist *os_sgl;
        struct fusion_context *fusion;
 
        fusion = instance->ctrl_context;
 
-       cmd->io_request->ChainOffset = 0;
+       if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
+               struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr;
+               sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
+               sgl_ptr_end->Flags = 0;
+       }
 
        sge_count = scsi_dma_map(scp);
 
@@ -1082,16 +1088,14 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
        if (sge_count > instance->max_num_sge || !sge_count)
                return sge_count;
 
-       if (sge_count > fusion->max_sge_in_main_msg) {
-               /* One element to store the chain info */
-               sge_idx = fusion->max_sge_in_main_msg - 1;
-       } else
-               sge_idx = sge_count;
-
        scsi_for_each_sg(scp, os_sgl, sge_count, i) {
                sgl_ptr->Length = sg_dma_len(os_sgl);
                sgl_ptr->Address = sg_dma_address(os_sgl);
                sgl_ptr->Flags = 0;
+               if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
+                       if (i == sge_count - 1)
+                               sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST;
+               }
                sgl_ptr++;
 
                sg_processed = i + 1;
@@ -1100,13 +1104,30 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                    (sge_count > fusion->max_sge_in_main_msg)) {
 
                        struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
-                       cmd->io_request->ChainOffset =
-                               fusion->chain_offset_io_request;
+                       if (instance->pdev->device ==
+                           PCI_DEVICE_ID_LSI_INVADER) {
+                               if ((cmd->io_request->IoFlags &
+                               MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
+                               MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
+                                       cmd->io_request->ChainOffset =
+                                               fusion->
+                                               chain_offset_io_request;
+                               else
+                                       cmd->io_request->ChainOffset = 0;
+                       } else
+                               cmd->io_request->ChainOffset =
+                                       fusion->chain_offset_io_request;
+
                        sg_chain = sgl_ptr;
                        /* Prepare chain element */
                        sg_chain->NextChainOffset = 0;
-                       sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT |
-                                          MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
+                       if (instance->pdev->device ==
+                           PCI_DEVICE_ID_LSI_INVADER)
+                               sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT;
+                       else
+                               sg_chain->Flags =
+                                       (IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+                                        MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
                        sg_chain->Length =  (sizeof(union MPI2_SGE_IO_UNION)
                                             *(sge_count - sg_processed));
                        sg_chain->Address = cmd->sg_frame_phys_addr;
@@ -1399,11 +1420,18 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                io_request->RaidContext.regLockFlags  = 0;
                fp_possible = 0;
        } else {
-               if (MR_BuildRaidContext(&io_info, &io_request->RaidContext,
+               if (MR_BuildRaidContext(instance, &io_info,
+                                       &io_request->RaidContext,
                                        local_map_ptr))
                        fp_possible = io_info.fpOkForIo;
        }
 
+       /* Use smp_processor_id() for now until cmd->request->cpu is CPU
+          id by default, not CPU group id, otherwise all MSI-X queues won't
+          be utilized */
+       cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ?
+               smp_processor_id() % instance->msix_vectors : 0;
+
        if (fp_possible) {
                megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp,
                                   local_map_ptr, start_lba_lo);
@@ -1412,6 +1440,20 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
                         << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+               if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
+                       if (io_request->RaidContext.regLockFlags ==
+                           REGION_TYPE_UNUSED)
+                               cmd->request_desc->SCSIIO.RequestFlags =
+                                       (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
+                                       MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+                       io_request->RaidContext.Type = MPI2_TYPE_CUDA;
+                       io_request->RaidContext.nseg = 0x1;
+                       io_request->IoFlags |=
+                         MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH;
+                       io_request->RaidContext.regLockFlags |=
+                         (MR_RL_FLAGS_GRANT_DESTINATION_CUDA |
+                          MR_RL_FLAGS_SEQ_NUM_ENABLE);
+               }
                if ((fusion->load_balance_info[device_id].loadBalanceFlag) &&
                    (io_info.isRead)) {
                        io_info.devHandle =
@@ -1426,11 +1468,23 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        } else {
                io_request->RaidContext.timeoutValue =
                        local_map_ptr->raidMap.fpPdIoTimeoutSec;
-               io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
-               io_request->DevHandle = device_id;
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
                         << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+               if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
+                       if (io_request->RaidContext.regLockFlags ==
+                           REGION_TYPE_UNUSED)
+                               cmd->request_desc->SCSIIO.RequestFlags =
+                                       (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
+                                       MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+                       io_request->RaidContext.Type = MPI2_TYPE_CUDA;
+                       io_request->RaidContext.regLockFlags |=
+                               (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 |
+                                MR_RL_FLAGS_SEQ_NUM_ENABLE);
+                       io_request->RaidContext.nseg = 0x1;
+               }
+               io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+               io_request->DevHandle = device_id;
        } /* Not FP */
 }
 
@@ -1513,8 +1567,10 @@ megasas_build_io_fusion(struct megasas_instance *instance,
        io_request->EEDPFlags = 0;
        io_request->Control = 0;
        io_request->EEDPBlockSize = 0;
-       io_request->IoFlags = 0;
+       io_request->ChainOffset = 0;
        io_request->RaidContext.RAIDFlags = 0;
+       io_request->RaidContext.Type = 0;
+       io_request->RaidContext.nseg = 0;
 
        memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
        /*
@@ -1612,7 +1668,6 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
 
        req_desc->Words = 0;
        cmd->request_desc = req_desc;
-       cmd->request_desc->Words = 0;
 
        if (megasas_build_io_fusion(instance, scmd, cmd)) {
                megasas_return_cmd_fusion(instance, cmd);
@@ -1647,7 +1702,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
  * Completes all commands that is in reply descriptor queue
  */
 int
-complete_cmd_fusion(struct megasas_instance *instance)
+complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 {
        union MPI2_REPLY_DESCRIPTORS_UNION *desc;
        struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
@@ -1667,7 +1722,9 @@ complete_cmd_fusion(struct megasas_instance *instance)
                return IRQ_HANDLED;
 
        desc = fusion->reply_frames_desc;
-       desc += fusion->last_reply_idx;
+       desc += ((MSIxIndex * fusion->reply_alloc_sz)/
+                sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
+               fusion->last_reply_idx[MSIxIndex];
 
        reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
 
@@ -1740,16 +1797,19 @@ complete_cmd_fusion(struct megasas_instance *instance)
                        break;
                }
 
-               fusion->last_reply_idx++;
-               if (fusion->last_reply_idx >= fusion->reply_q_depth)
-                       fusion->last_reply_idx = 0;
+               fusion->last_reply_idx[MSIxIndex]++;
+               if (fusion->last_reply_idx[MSIxIndex] >=
+                   fusion->reply_q_depth)
+                       fusion->last_reply_idx[MSIxIndex] = 0;
 
                desc->Words = ULLONG_MAX;
                num_completed++;
 
                /* Get the next reply descriptor */
-               if (!fusion->last_reply_idx)
-                       desc = fusion->reply_frames_desc;
+               if (!fusion->last_reply_idx[MSIxIndex])
+                       desc = fusion->reply_frames_desc +
+                               ((MSIxIndex * fusion->reply_alloc_sz)/
+                                sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
                else
                        desc++;
 
@@ -1769,7 +1829,7 @@ complete_cmd_fusion(struct megasas_instance *instance)
                return IRQ_NONE;
 
        wmb();
-       writel(fusion->last_reply_idx,
+       writel((MSIxIndex << 24) | fusion->last_reply_idx[MSIxIndex],
               &instance->reg_set->reply_post_host_index);
        megasas_check_and_restore_queue_depth(instance);
        return IRQ_HANDLED;
@@ -1787,6 +1847,9 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
        struct megasas_instance *instance =
                (struct megasas_instance *)instance_addr;
        unsigned long flags;
+       u32 count, MSIxIndex;
+
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
 
        /* If we have already declared adapter dead, donot complete cmds */
        spin_lock_irqsave(&instance->hba_lock, flags);
@@ -1797,7 +1860,8 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
        spin_unlock_irqrestore(&instance->hba_lock, flags);
 
        spin_lock_irqsave(&instance->completion_lock, flags);
-       complete_cmd_fusion(instance);
+       for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
+               complete_cmd_fusion(instance, MSIxIndex);
        spin_unlock_irqrestore(&instance->completion_lock, flags);
 }
 
@@ -1806,20 +1870,24 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
  */
 irqreturn_t megasas_isr_fusion(int irq, void *devp)
 {
-       struct megasas_instance *instance = (struct megasas_instance *)devp;
+       struct megasas_irq_context *irq_context = devp;
+       struct megasas_instance *instance = irq_context->instance;
        u32 mfiStatus, fw_state;
 
-       if (!instance->msi_flag) {
+       if (!instance->msix_vectors) {
                mfiStatus = instance->instancet->clear_intr(instance->reg_set);
                if (!mfiStatus)
                        return IRQ_NONE;
        }
 
        /* If we are resetting, bail */
-       if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
+       if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags)) {
+               instance->instancet->clear_intr(instance->reg_set);
                return IRQ_HANDLED;
+       }
 
-       if (!complete_cmd_fusion(instance)) {
+       if (!complete_cmd_fusion(instance, irq_context->MSIxIndex)) {
+               instance->instancet->clear_intr(instance->reg_set);
                /* 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;
@@ -1866,6 +1934,14 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
 
        fusion = instance->ctrl_context;
        io_req = cmd->io_request;
+
+       if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) {
+               struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end =
+                       (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL;
+               sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
+               sgl_ptr_end->Flags = 0;
+       }
+
        mpi25_ieee_chain =
          (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
 
@@ -1928,15 +2004,12 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance,
                          struct megasas_cmd *cmd)
 {
        union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
-       union desc_value d_val;
 
        req_desc = build_mpt_cmd(instance, cmd);
        if (!req_desc) {
                printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n");
                return;
        }
-       d_val.word = req_desc->Words;
-
        instance->instancet->fire_cmd(instance, req_desc->u.low,
                                      req_desc->u.high, instance->reg_set);
 }
@@ -2029,14 +2102,16 @@ out:
 
 void  megasas_reset_reply_desc(struct megasas_instance *instance)
 {
-       int i;
+       int i, count;
        struct fusion_context *fusion;
        union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
 
        fusion = instance->ctrl_context;
-       fusion->last_reply_idx = 0;
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+       for (i = 0 ; i < count ; i++)
+               fusion->last_reply_idx[i] = 0;
        reply_desc = fusion->reply_frames_desc;
-       for (i = 0 ; i < fusion->reply_q_depth; i++, reply_desc++)
+       for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++)
                reply_desc->Words = ULLONG_MAX;
 }
 
@@ -2057,8 +2132,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
        if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
                printk(KERN_WARNING "megaraid_sas: Hardware critical error, "
                       "returning FAILED.\n");
-               retval = FAILED;
-               goto out;
+               return FAILED;
        }
 
        mutex_lock(&instance->reset_mutex);
@@ -2173,7 +2247,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
                        }
 
                        /* Wait for FW to become ready */
-                       if (megasas_transition_to_ready(instance)) {
+                       if (megasas_transition_to_ready(instance, 1)) {
                                printk(KERN_WARNING "megaraid_sas: Failed to "
                                       "transition controller to ready.\n");
                                continue;
@@ -2186,6 +2260,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
                                continue;
                        }
 
+                       clear_bit(MEGASAS_FUSION_IN_RESET,
+                                 &instance->reset_flags);
                        instance->instancet->enable_intr(instance->reg_set);
                        instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
 
@@ -2247,6 +2323,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost)
                megaraid_sas_kill_hba(instance);
                retval = FAILED;
        } else {
+               clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
                instance->instancet->enable_intr(instance->reg_set);
                instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
        }