diff options
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas_base.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 156 |
1 files changed, 121 insertions, 35 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index f2cf768c896..ec09d5c2ed9 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2536,7 +2536,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; } @@ -2594,16 +2594,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); @@ -3488,6 +3486,7 @@ static int megasas_init_fw(struct megasas_instance *instance) 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); @@ -3541,9 +3540,33 @@ static int megasas_init_fw(struct megasas_instance *instance) /* 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)) @@ -3958,7 +3981,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; @@ -4126,11 +4149,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); @@ -4174,8 +4218,12 @@ 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) || (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) @@ -4183,7 +4231,7 @@ fail_irq: 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) @@ -4299,6 +4347,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; @@ -4322,9 +4371,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); @@ -4342,7 +4396,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; @@ -4380,8 +4434,9 @@ megasas_resume(struct pci_dev *pdev) 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: @@ -4411,11 +4466,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); @@ -4512,9 +4588,13 @@ 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) { @@ -4560,14 +4640,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); } |