scsi: megaraid_sas: Fix data integrity failure for JBOD (passthrough) devices
[pandora-kernel.git] / drivers / scsi / megaraid / megaraid_sas_base.c
index 776d019..6e1ae59 100644 (file)
@@ -18,7 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  *  FILE: megaraid_sas_base.c
- *  Version : v00.00.05.40-rc1
+ *  Version : v00.00.06.12-rc1
  *
  *  Authors: LSI Corporation
  *           Sreenivas Bagalkote
@@ -84,7 +84,7 @@ MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux@lsi.com");
 MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
 
-int megasas_transition_to_ready(struct megasas_instance *instance);
+int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
 static int megasas_get_pd_list(struct megasas_instance *instance);
 static int megasas_issue_init_mfi(struct megasas_instance *instance);
 static int megasas_register_aen(struct megasas_instance *instance,
@@ -114,6 +114,8 @@ static struct pci_device_id megasas_pci_table[] = {
        /* 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_INVADER)},
+       /* Invader */
        {}
 };
 
@@ -213,6 +215,10 @@ megasas_return_cmd(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_INVADER) &&
+           (reset_devices))
+               cmd->frame->hdr.cmd = MFI_CMD_INVALID;
        list_add_tail(&cmd->list, &instance->cmd_pool);
 
        spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
@@ -1480,16 +1486,13 @@ megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd
                goto out_done;
        }
 
-       switch (scmd->cmnd[0]) {
-       case SYNCHRONIZE_CACHE:
-               /*
-                * FW takes care of flush cache on its own
-                * No need to send it down
-                */
+       /*
+        * FW takes care of flush cache on its own for Virtual Disk.
+        * No need to send it down for VD. For JBOD send SYNCHRONIZE_CACHE to FW.
+        */
+       if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) && MEGASAS_IS_LOGICAL(scmd)) {
                scmd->result = DID_OK << 16;
                goto out_done;
-       default:
-               break;
        }
 
        if (instance->instancet->build_and_issue_cmd(instance, scmd)) {
@@ -1583,7 +1586,8 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance)
 {
        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_FUSION) ||
+           (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) {
                writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
        } else {
                writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
@@ -1907,7 +1911,6 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
 static enum
 blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
-       struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
        struct megasas_instance *instance;
        unsigned long flags;
 
@@ -1916,7 +1919,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
                return BLK_EH_NOT_HANDLED;
        }
 
-       instance = cmd->instance;
+       instance = (struct megasas_instance *)scmd->device->host->hostdata;
        if (!(instance->flag & MEGASAS_FW_BUSY)) {
                /* FW is busy, throttle IO */
                spin_lock_irqsave(instance->host->host_lock, flags);
@@ -1957,7 +1960,8 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
        /*
         * First wait for all commands to complete
         */
-       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_INVADER))
                ret = megasas_reset_fusion(scmd->device->host);
        else
                ret = megasas_generic_reset(scmd);
@@ -2161,7 +2165,16 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                cmd->scmd->SCp.ptr = NULL;
 
        switch (hdr->cmd) {
-
+       case MFI_CMD_INVALID:
+               /* Some older 1068 controller FW may keep a pended
+                  MR_DCMD_CTRL_EVENT_GET_INFO left over from the main kernel
+                  when booting the kdump kernel.  Ignore this command to
+                  prevent a kernel panic on shutdown of the kdump kernel. */
+               printk(KERN_WARNING "megaraid_sas: MFI_CMD_INVALID command "
+                      "completed.\n");
+               printk(KERN_WARNING "megaraid_sas: If you have a controller "
+                      "other than PERC5, please upgrade your firmware.\n");
+               break;
        case MFI_CMD_PD_SCSI_IO:
        case MFI_CMD_LD_SCSI_IO:
 
@@ -2477,7 +2490,7 @@ process_fw_state_change_wq(struct work_struct *work)
                        msleep(1000);
                }
 
-               if (megasas_transition_to_ready(instance)) {
+               if (megasas_transition_to_ready(instance, 1)) {
                        printk(KERN_NOTICE "megaraid_sas:adapter not ready\n");
 
                        megaraid_sas_kill_hba(instance);
@@ -2532,7 +2545,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
                                                instance->reg_set)
                                                ) == 0) {
                /* Hardware may not set outbound_intr_status in MSI-X mode */
-               if (!instance->msi_flag)
+               if (!instance->msix_vectors)
                        return IRQ_NONE;
        }
 
@@ -2590,16 +2603,14 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
  */
 static irqreturn_t megasas_isr(int irq, void *devp)
 {
-       struct megasas_instance *instance;
+       struct megasas_irq_context *irq_context = devp;
+       struct megasas_instance *instance = irq_context->instance;
        unsigned long flags;
        irqreturn_t     rc;
 
-       if (atomic_read(
-               &(((struct megasas_instance *)devp)->fw_reset_no_pci_access)))
+       if (atomic_read(&instance->fw_reset_no_pci_access))
                return IRQ_HANDLED;
 
-       instance = (struct megasas_instance *)devp;
-
        spin_lock_irqsave(&instance->hba_lock, flags);
        rc =  megasas_deplete_reply_queue(instance, DID_OK);
        spin_unlock_irqrestore(&instance->hba_lock, flags);
@@ -2617,7 +2628,7 @@ static irqreturn_t megasas_isr(int irq, void *devp)
  * has to wait for the ready state.
  */
 int
-megasas_transition_to_ready(struct megasas_instance* instance)
+megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
 {
        int i;
        u8 max_wait;
@@ -2639,11 +2650,13 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                switch (fw_state) {
 
                case MFI_STATE_FAULT:
-
                        printk(KERN_DEBUG "megasas: FW in FAULT state!!\n");
-                       max_wait = MEGASAS_RESET_WAIT_TIME;
-                       cur_state = MFI_STATE_FAULT;
-                       break;
+                       if (ocr) {
+                               max_wait = MEGASAS_RESET_WAIT_TIME;
+                               cur_state = MFI_STATE_FAULT;
+                               break;
+                       } else
+                               return -ENODEV;
 
                case MFI_STATE_WAIT_HANDSHAKE:
                        /*
@@ -2654,7 +2667,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                                (instance->pdev->device ==
                                 PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
                                (instance->pdev->device ==
-                                PCI_DEVICE_ID_LSI_FUSION)) {
+                                PCI_DEVICE_ID_LSI_FUSION) ||
+                               (instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_INVADER)) {
                                writel(
                                  MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
                                  &instance->reg_set->doorbell);
@@ -2674,7 +2689,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                                (instance->pdev->device ==
                                 PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
                            (instance->pdev->device ==
-                            PCI_DEVICE_ID_LSI_FUSION)) {
+                            PCI_DEVICE_ID_LSI_FUSION) ||
+                           (instance->pdev->device ==
+                            PCI_DEVICE_ID_LSI_INVADER)) {
                                writel(MFI_INIT_HOTPLUG,
                                       &instance->reg_set->doorbell);
                        } else
@@ -2695,11 +2712,15 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                                (instance->pdev->device ==
                                PCI_DEVICE_ID_LSI_SAS0071SKINNY)  ||
                                (instance->pdev->device
-                                       == PCI_DEVICE_ID_LSI_FUSION)) {
+                                       == PCI_DEVICE_ID_LSI_FUSION) ||
+                               (instance->pdev->device
+                                       == PCI_DEVICE_ID_LSI_INVADER)) {
                                writel(MFI_RESET_FLAGS,
                                        &instance->reg_set->doorbell);
-                               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_INVADER)) {
                                        for (i = 0; i < (10 * 1000); i += 20) {
                                                if (readl(
                                                            &instance->
@@ -2922,6 +2943,10 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
                memset(cmd->frame, 0, total_sz);
                cmd->frame->io.context = cmd->index;
                cmd->frame->io.pad_0 = 0;
+               if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
+                   (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
+                   (reset_devices))
+                       cmd->frame->hdr.cmd = MFI_CMD_INVALID;
        }
 
        return 0;
@@ -3471,21 +3496,23 @@ static int megasas_init_fw(struct megasas_instance *instance)
        u32 max_sectors_1;
        u32 max_sectors_2;
        u32 tmp_sectors, msix_enable;
+       resource_size_t base_addr;
        struct megasas_register_set __iomem *reg_set;
        struct megasas_ctrl_info *ctrl_info;
        unsigned long bar_list;
+       int i;
 
        /* Find first memory bar */
        bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
        instance->bar = find_first_bit(&bar_list, sizeof(unsigned long));
-       instance->base_addr = pci_resource_start(instance->pdev, instance->bar);
-       if (pci_request_selected_regions(instance->pdev, instance->bar,
+       if (pci_request_selected_regions(instance->pdev, 1<<instance->bar,
                                         "megasas: LSI")) {
                printk(KERN_DEBUG "megasas: IO memory region busy!\n");
                return -EBUSY;
        }
 
-       instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
+       base_addr = pci_resource_start(instance->pdev, instance->bar);
+       instance->reg_set = ioremap_nocache(base_addr, 8192);
 
        if (!instance->reg_set) {
                printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
@@ -3496,6 +3523,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_INVADER:
                instance->instancet = &megasas_instance_template_fusion;
                break;
        case PCI_DEVICE_ID_LSI_SAS1078R:
@@ -3517,18 +3545,52 @@ static int megasas_init_fw(struct megasas_instance *instance)
                break;
        }
 
-       /*
-        * We expect the FW state to be READY
-        */
-       if (megasas_transition_to_ready(instance))
-               goto fail_ready_state;
+       if (megasas_transition_to_ready(instance, 0)) {
+               atomic_set(&instance->fw_reset_no_pci_access, 1);
+               instance->instancet->adp_reset
+                       (instance, instance->reg_set);
+               atomic_set(&instance->fw_reset_no_pci_access, 0);
+               dev_info(&instance->pdev->dev,
+                       "megasas: FW restarted successfully from %s!\n",
+                       __func__);
+
+               /*waitting for about 30 second before retry*/
+               ssleep(30);
+
+               if (megasas_transition_to_ready(instance, 0))
+                       goto fail_ready_state;
+       }
 
        /* Check if MSI-X is supported while in ready state */
        msix_enable = (instance->instancet->read_fw_status_reg(reg_set) &
                       0x4000000) >> 0x1a;
-       if (msix_enable && !msix_disable &&
-           !pci_enable_msix(instance->pdev, &instance->msixentry, 1))
-               instance->msi_flag = 1;
+       if (msix_enable && !msix_disable) {
+               /* Check max MSI-X vectors */
+               if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+                   (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) {
+                       instance->msix_vectors = (readl(&instance->reg_set->
+                                                       outbound_scratch_pad_2
+                                                         ) & 0x1F) + 1;
+               } else
+                       instance->msix_vectors = 1;
+               /* Don't bother allocating more MSI-X vectors than cpus */
+               instance->msix_vectors = min(instance->msix_vectors,
+                                            (unsigned int)num_online_cpus());
+               for (i = 0; i < instance->msix_vectors; i++)
+                       instance->msixentry[i].entry = i;
+               i = pci_enable_msix(instance->pdev, instance->msixentry,
+                                   instance->msix_vectors);
+               if (i >= 0) {
+                       if (i) {
+                               if (!pci_enable_msix(instance->pdev,
+                                                    instance->msixentry, i))
+                                       instance->msix_vectors = i;
+                               else
+                                       instance->msix_vectors = 0;
+                       }
+               } else
+                       instance->msix_vectors = 0;
+       }
 
        /* Get operational params, sge flags, send init cmd to controller */
        if (instance->instancet->init_adapter(instance))
@@ -3571,7 +3633,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
        }
 
        instance->max_sectors_per_req = instance->max_num_sge *
-                                               PAGE_SIZE / 512;
+                                               SGE_BUFFER_SIZE / 512;
        if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
                instance->max_sectors_per_req = tmp_sectors;
 
@@ -3596,7 +3658,7 @@ fail_ready_state:
        iounmap(instance->reg_set);
 
       fail_ioremap:
-       pci_release_selected_regions(instance->pdev, instance->bar);
+       pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 
        return -EINVAL;
 }
@@ -3617,7 +3679,7 @@ static void megasas_release_mfi(struct megasas_instance *instance)
 
        iounmap(instance->reg_set);
 
-       pci_release_selected_regions(instance->pdev, instance->bar);
+       pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 }
 
 /**
@@ -3892,7 +3954,8 @@ static int megasas_io_attach(struct megasas_instance *instance)
        host->max_cmd_len = 16;
 
        /* Fusion only supports host reset */
-       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_INVADER)) {
                host->hostt->eh_device_reset_handler = NULL;
                host->hostt->eh_bus_reset_handler = NULL;
        }
@@ -3942,7 +4005,7 @@ fail_set_dma_mask:
 static int __devinit
 megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       int rval, pos;
+       int rval, pos, i, j;
        struct Scsi_Host *host;
        struct megasas_instance *instance;
        u16 control = 0;
@@ -4002,6 +4065,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_INVADER:
        {
                struct fusion_context *fusion;
 
@@ -4069,7 +4133,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        spin_lock_init(&instance->cmd_pool_lock);
        spin_lock_init(&instance->hba_lock);
        spin_lock_init(&instance->completion_lock);
-       spin_lock_init(&poll_aen_lock);
 
        mutex_init(&instance->aen_mutex);
        mutex_init(&instance->reset_mutex);
@@ -4094,7 +4157,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        instance->last_time = 0;
        instance->disableOnlineCtrlReset = 1;
 
-       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_INVADER))
                INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
        else
                INIT_WORK(&instance->work_init, process_fw_state_change_wq);
@@ -4108,11 +4172,32 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /*
         * Register IRQ
         */
-       if (request_irq(instance->msi_flag ? instance->msixentry.vector :
-                       pdev->irq, instance->instancet->service_isr,
-                       IRQF_SHARED, "megasas", instance)) {
-               printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
-               goto fail_irq;
+       if (instance->msix_vectors) {
+               for (i = 0 ; i < instance->msix_vectors; i++) {
+                       instance->irq_context[i].instance = instance;
+                       instance->irq_context[i].MSIxIndex = i;
+                       if (request_irq(instance->msixentry[i].vector,
+                                       instance->instancet->service_isr, 0,
+                                       "megasas",
+                                       &instance->irq_context[i])) {
+                               printk(KERN_DEBUG "megasas: Failed to "
+                                      "register IRQ for vector %d.\n", i);
+                               for (j = 0 ; j < i ; j++)
+                                       free_irq(
+                                               instance->msixentry[j].vector,
+                                               &instance->irq_context[j]);
+                               goto fail_irq;
+                       }
+               }
+       } else {
+               instance->irq_context[0].instance = instance;
+               instance->irq_context[0].MSIxIndex = 0;
+               if (request_irq(pdev->irq, instance->instancet->service_isr,
+                               IRQF_SHARED, "megasas",
+                               &instance->irq_context[0])) {
+                       printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
+                       goto fail_irq;
+               }
        }
 
        instance->instancet->enable_intr(instance->reg_set);
@@ -4156,15 +4241,20 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        pci_set_drvdata(pdev, NULL);
        instance->instancet->disable_intr(instance->reg_set);
-       free_irq(instance->msi_flag ? instance->msixentry.vector :
-                instance->pdev->irq, instance);
+       if (instance->msix_vectors)
+               for (i = 0 ; i < instance->msix_vectors; i++)
+                       free_irq(instance->msixentry[i].vector,
+                                &instance->irq_context[i]);
+       else
+               free_irq(instance->pdev->irq, &instance->irq_context[0]);
 fail_irq:
-       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_INVADER))
                megasas_release_fusion(instance);
        else
                megasas_release_mfi(instance);
       fail_init_mfi:
-       if (instance->msi_flag)
+       if (instance->msix_vectors)
                pci_disable_msix(instance->pdev);
       fail_alloc_dma_buf:
        if (instance->evt_detail)
@@ -4280,6 +4370,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct Scsi_Host *host;
        struct megasas_instance *instance;
+       int i;
 
        instance = pci_get_drvdata(pdev);
        host = instance->host;
@@ -4303,9 +4394,14 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 
        pci_set_drvdata(instance->pdev, instance);
        instance->instancet->disable_intr(instance->reg_set);
-       free_irq(instance->msi_flag ? instance->msixentry.vector :
-                instance->pdev->irq, instance);
-       if (instance->msi_flag)
+
+       if (instance->msix_vectors)
+               for (i = 0 ; i < instance->msix_vectors; i++)
+                       free_irq(instance->msixentry[i].vector,
+                                &instance->irq_context[i]);
+       else
+               free_irq(instance->pdev->irq, &instance->irq_context[0]);
+       if (instance->msix_vectors)
                pci_disable_msix(instance->pdev);
 
        pci_save_state(pdev);
@@ -4323,7 +4419,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 static int
 megasas_resume(struct pci_dev *pdev)
 {
-       int rval;
+       int rval, i, j;
        struct Scsi_Host *host;
        struct megasas_instance *instance;
 
@@ -4357,15 +4453,17 @@ megasas_resume(struct pci_dev *pdev)
        /*
         * We expect the FW state to be READY
         */
-       if (megasas_transition_to_ready(instance))
+       if (megasas_transition_to_ready(instance, 0))
                goto fail_ready_state;
 
        /* Now re-enable MSI-X */
-       if (instance->msi_flag)
-               pci_enable_msix(instance->pdev, &instance->msixentry, 1);
+       if (instance->msix_vectors)
+               pci_enable_msix(instance->pdev, instance->msixentry,
+                               instance->msix_vectors);
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_INVADER:
        {
                megasas_reset_reply_desc(instance);
                if (megasas_ioc_init_fusion(instance)) {
@@ -4391,11 +4489,32 @@ megasas_resume(struct pci_dev *pdev)
        /*
         * Register IRQ
         */
-       if (request_irq(instance->msi_flag ? instance->msixentry.vector :
-                       pdev->irq, instance->instancet->service_isr,
-                       IRQF_SHARED, "megasas", instance)) {
-               printk(KERN_ERR "megasas: Failed to register IRQ\n");
-               goto fail_irq;
+       if (instance->msix_vectors) {
+               for (i = 0 ; i < instance->msix_vectors; i++) {
+                       instance->irq_context[i].instance = instance;
+                       instance->irq_context[i].MSIxIndex = i;
+                       if (request_irq(instance->msixentry[i].vector,
+                                       instance->instancet->service_isr, 0,
+                                       "megasas",
+                                       &instance->irq_context[i])) {
+                               printk(KERN_DEBUG "megasas: Failed to "
+                                      "register IRQ for vector %d.\n", i);
+                               for (j = 0 ; j < i ; j++)
+                                       free_irq(
+                                               instance->msixentry[j].vector,
+                                               &instance->irq_context[j]);
+                               goto fail_irq;
+                       }
+               }
+       } else {
+               instance->irq_context[0].instance = instance;
+               instance->irq_context[0].MSIxIndex = 0;
+               if (request_irq(pdev->irq, instance->instancet->service_isr,
+                               IRQF_SHARED, "megasas",
+                               &instance->irq_context[0])) {
+                       printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
+                       goto fail_irq;
+               }
        }
 
        instance->instancet->enable_intr(instance->reg_set);
@@ -4492,13 +4611,18 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
 
        instance->instancet->disable_intr(instance->reg_set);
 
-       free_irq(instance->msi_flag ? instance->msixentry.vector :
-                instance->pdev->irq, instance);
-       if (instance->msi_flag)
+       if (instance->msix_vectors)
+               for (i = 0 ; i < instance->msix_vectors; i++)
+                       free_irq(instance->msixentry[i].vector,
+                                &instance->irq_context[i]);
+       else
+               free_irq(instance->pdev->irq, &instance->irq_context[0]);
+       if (instance->msix_vectors)
                pci_disable_msix(instance->pdev);
 
        switch (instance->pdev->device) {
        case PCI_DEVICE_ID_LSI_FUSION:
+       case PCI_DEVICE_ID_LSI_INVADER:
                megasas_release_fusion(instance);
                for (i = 0; i < 2 ; i++)
                        if (fusion->ld_map[i])
@@ -4539,14 +4663,20 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
  */
 static void megasas_shutdown(struct pci_dev *pdev)
 {
+       int i;
        struct megasas_instance *instance = pci_get_drvdata(pdev);
+
        instance->unload = 1;
        megasas_flush_cache(instance);
        megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
        instance->instancet->disable_intr(instance->reg_set);
-       free_irq(instance->msi_flag ? instance->msixentry.vector :
-                instance->pdev->irq, instance);
-       if (instance->msi_flag)
+       if (instance->msix_vectors)
+               for (i = 0 ; i < instance->msix_vectors; i++)
+                       free_irq(instance->msixentry[i].vector,
+                                &instance->irq_context[i]);
+       else
+               free_irq(instance->pdev->irq, &instance->irq_context[0]);
+       if (instance->msix_vectors)
                pci_disable_msix(instance->pdev);
 }
 
@@ -4764,10 +4894,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                                    sense, sense_handle);
        }
 
-       for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
-               dma_free_coherent(&instance->pdev->dev,
-                                   kern_sge32[i].length,
-                                   kbuff_arr[i], kern_sge32[i].phys_addr);
+       for (i = 0; i < ioc->sge_count; i++) {
+               if (kbuff_arr[i])
+                       dma_free_coherent(&instance->pdev->dev,
+                                         kern_sge32[i].length,
+                                         kbuff_arr[i],
+                                         kern_sge32[i].phys_addr);
        }
 
        megasas_return_cmd(instance, cmd);
@@ -4948,6 +5080,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
        int i;
        int error = 0;
        compat_uptr_t ptr;
+       unsigned long local_raw_ptr;
+       u32 local_sense_off;
+       u32 local_sense_len;
 
        if (clear_user(ioc, sizeof(*ioc)))
                return -EFAULT;
@@ -4965,9 +5100,15 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
         * sense_len is not null, so prepare the 64bit value under
         * the same condition.
         */
-       if (ioc->sense_len) {
+       if (get_user(local_raw_ptr, ioc->frame.raw) ||
+               get_user(local_sense_off, &ioc->sense_off) ||
+               get_user(local_sense_len, &ioc->sense_len))
+               return -EFAULT;
+
+
+       if (local_sense_len) {
                void __user **sense_ioc_ptr =
-                       (void __user **)(ioc->frame.raw + ioc->sense_off);
+                       (void __user **)((u8*)local_raw_ptr + local_sense_off);
                compat_uptr_t *sense_cioc_ptr =
                        (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
                if (get_user(ptr, sense_cioc_ptr) ||
@@ -5397,6 +5538,8 @@ static int __init megasas_init(void)
        printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
               MEGASAS_EXT_VERSION);
 
+       spin_lock_init(&poll_aen_lock);
+
        support_poll_for_event = 2;
        support_device_change = 1;