diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-29 03:44:18 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-29 03:44:18 +0400 |
commit | ec7ae517537ae5c7b0b2cd7f562dfa3e7a05b954 (patch) | |
tree | e6b0c64a51a7c0aa0efd09d4f7a80872e3b1657a /drivers/scsi/megaraid | |
parent | 97d2eb13a019ec09cc1a7ea2d3705c0b117b3c0d (diff) | |
parent | 590134fa78fbdbe5fea78c7ae0b2c3364bc9572f (diff) | |
download | linux-ec7ae517537ae5c7b0b2cd7f562dfa3e7a05b954.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (204 commits)
[SCSI] qla4xxx: export address/port of connection (fix udev disk names)
[SCSI] ipr: Fix BUG on adapter dump timeout
[SCSI] megaraid_sas: Fix instance access in megasas_reset_timer
[SCSI] hpsa: change confusing message to be more clear
[SCSI] iscsi class: fix vlan configuration
[SCSI] qla4xxx: fix data alignment and use nl helpers
[SCSI] iscsi class: fix link local mispelling
[SCSI] iscsi class: Replace iscsi_get_next_target_id with IDA
[SCSI] aacraid: use lower snprintf() limit
[SCSI] lpfc 8.3.27: Change driver version to 8.3.27
[SCSI] lpfc 8.3.27: T10 additions for SLI4
[SCSI] lpfc 8.3.27: Fix queue allocation failure recovery
[SCSI] lpfc 8.3.27: Change algorithm for getting physical port name
[SCSI] lpfc 8.3.27: Changed worst case mailbox timeout
[SCSI] lpfc 8.3.27: Miscellanous logic and interface fixes
[SCSI] megaraid_sas: Changelog and version update
[SCSI] megaraid_sas: Add driver workaround for PERC5/1068 kdump kernel panic
[SCSI] megaraid_sas: Add multiple MSI-X vector/multiple reply queue support
[SCSI] megaraid_sas: Add support for MegaRAID 9360/9380 12GB/s controllers
[SCSI] megaraid_sas: Clear FUSION_IN_RESET before enabling interrupts
...
Diffstat (limited to 'drivers/scsi/megaraid')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 22 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 239 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fp.c | 26 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.c | 193 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.h | 19 |
5 files changed, 365 insertions, 134 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 3948a00d81f4..dd94c7d574fb 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -33,9 +33,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.05.40-rc1" -#define MEGASAS_RELDATE "Jul. 26, 2011" -#define MEGASAS_EXT_VERSION "Tue. Jul. 26 17:00:00 PDT 2011" +#define MEGASAS_VERSION "00.00.06.12-rc1" +#define MEGASAS_RELDATE "Oct. 5, 2011" +#define MEGASAS_EXT_VERSION "Wed. Oct. 5 17:00:00 PDT 2011" /* * Device IDs @@ -48,6 +48,7 @@ #define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073 #define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071 #define PCI_DEVICE_ID_LSI_FUSION 0x005b +#define PCI_DEVICE_ID_LSI_INVADER 0x005d /* * ===================================== @@ -138,6 +139,7 @@ #define MFI_CMD_ABORT 0x06 #define MFI_CMD_SMP 0x07 #define MFI_CMD_STP 0x08 +#define MFI_CMD_INVALID 0xff #define MR_DCMD_CTRL_GET_INFO 0x01010000 #define MR_DCMD_LD_GET_LIST 0x03010000 @@ -221,6 +223,7 @@ enum MFI_STAT { MFI_STAT_RESERVATION_IN_PROGRESS = 0x36, MFI_STAT_I2C_ERRORS_DETECTED = 0x37, MFI_STAT_PCI_ERRORS_DETECTED = 0x38, + MFI_STAT_CONFIG_SEQ_MISMATCH = 0x67, MFI_STAT_INVALID_STATUS = 0xFF }; @@ -716,7 +719,7 @@ struct megasas_ctrl_info { #define MEGASAS_DEFAULT_INIT_ID -1 #define MEGASAS_MAX_LUN 8 #define MEGASAS_MAX_LD 64 -#define MEGASAS_DEFAULT_CMD_PER_LUN 128 +#define MEGASAS_DEFAULT_CMD_PER_LUN 256 #define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \ MEGASAS_MAX_DEV_PER_CHANNEL) #define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \ @@ -755,6 +758,7 @@ struct megasas_ctrl_info { #define MEGASAS_INT_CMDS 32 #define MEGASAS_SKINNY_INT_CMDS 5 +#define MEGASAS_MAX_MSIX_QUEUES 16 /* * FW can accept both 32 and 64 bit SGLs. We want to allocate 32/64 bit * SGLs based on the size of dma_addr_t @@ -1276,6 +1280,11 @@ struct megasas_aen_event { struct megasas_instance *instance; }; +struct megasas_irq_context { + struct megasas_instance *instance; + u32 MSIxIndex; +}; + struct megasas_instance { u32 *producer; @@ -1349,8 +1358,9 @@ struct megasas_instance { /* Ptr to hba specific information */ void *ctrl_context; - u8 msi_flag; - struct msix_entry msixentry; + unsigned int msix_vectors; + struct msix_entry msixentry[MEGASAS_MAX_MSIX_QUEUES]; + struct megasas_irq_context irq_context[MEGASAS_MAX_MSIX_QUEUES]; u64 map_id; struct megasas_cmd *map_update_cmd; unsigned long bar; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 776d01988660..29a994f9c4f1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -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); @@ -1583,7 +1589,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 +1914,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 +1922,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 +1963,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 +2168,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 +2493,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 +2548,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 +2606,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 +2631,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 +2653,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 +2670,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 +2692,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 +2715,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 +2946,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; @@ -3474,6 +3502,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); @@ -3496,6 +3525,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: @@ -3520,15 +3550,39 @@ static int megasas_init_fw(struct megasas_instance *instance) /* * 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; /* 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)) @@ -3892,7 +3946,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 +3997,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 +4057,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; @@ -4094,7 +4150,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 +4165,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 +4234,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 +4363,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 +4387,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 +4412,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 +4446,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 +4482,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 +4604,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 +4656,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); } diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 5a5af1fe7581..5255dd688aca 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -52,6 +52,7 @@ #include <scsi/scsi_host.h> #include "megaraid_sas_fusion.h" +#include "megaraid_sas.h" #include <asm/div64.h> #define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) @@ -226,8 +227,9 @@ u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk, * span - Span number * block - Absolute Block number in the physical disk */ -u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock, - u16 *pDevHandle, struct RAID_CONTEXT *pRAID_Context, +u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, + u16 stripRef, u64 *pdBlock, u16 *pDevHandle, + struct RAID_CONTEXT *pRAID_Context, struct MR_FW_RAID_MAP_ALL *map) { struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); @@ -279,7 +281,8 @@ u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock, *pDevHandle = MR_PdDevHandleGet(pd, map); else { *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */ - if (raid->level >= 5) + if ((raid->level >= 5) && + (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER)) pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { /* Get alternate Pd. */ @@ -306,7 +309,8 @@ u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock, * This function will return 0 if region lock was acquired OR return num strips */ 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) { @@ -394,8 +398,12 @@ MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info, } pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec; - pRAID_Context->regLockFlags = (isRead) ? REGION_TYPE_SHARED_READ : - raid->regTypeReqOnWrite; + if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) + pRAID_Context->regLockFlags = (isRead) ? + raid->regTypeReqOnRead : raid->regTypeReqOnWrite; + else + pRAID_Context->regLockFlags = (isRead) ? + REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; pRAID_Context->VirtualDiskTgtId = raid->targetId; pRAID_Context->regLockRowLBA = regStart; pRAID_Context->regLockLength = regSize; @@ -404,7 +412,8 @@ MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info, /*Get Phy Params only if FP capable, or else leave it to MR firmware to do the calculation.*/ if (io_info->fpOkForIo) { - retval = MR_GetPhyParams(ld, start_strip, ref_in_start_stripe, + retval = MR_GetPhyParams(instance, ld, start_strip, + ref_in_start_stripe, &io_info->pdBlock, &io_info->devHandle, pRAID_Context, map); @@ -415,7 +424,8 @@ MR_BuildRaidContext(struct IO_REQUEST_INFO *io_info, } else if (isRead) { uint stripIdx; for (stripIdx = 0; stripIdx < num_strips; stripIdx++) { - if (!MR_GetPhyParams(ld, start_strip + stripIdx, + if (!MR_GetPhyParams(instance, ld, + start_strip + stripIdx, ref_in_start_stripe, &io_info->pdBlock, &io_info->devHandle, diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index f13e7abd345a..bfd87fab39aa 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -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, ®s->outbound_intr_status); + readl(®s->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(®s->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; } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 82b577a72c8b..088c9f91da95 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -43,6 +43,15 @@ #define HOST_DIAG_WRITE_ENABLE 0x80 #define HOST_DIAG_RESET_ADAPTER 0x4 #define MEGASAS_FUSION_MAX_RESET_TRIES 3 +#define MAX_MSIX_QUEUES_FUSION 16 + +/* Invader defines */ +#define MPI2_TYPE_CUDA 0x2 +#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH 0x4000 +#define MR_RL_FLAGS_GRANT_DESTINATION_CPU0 0x00 +#define MR_RL_FLAGS_GRANT_DESTINATION_CPU1 0x10 +#define MR_RL_FLAGS_GRANT_DESTINATION_CUDA 0x80 +#define MR_RL_FLAGS_SEQ_NUM_ENABLE 0x8 /* T10 PI defines */ #define MR_PROT_INFO_TYPE_CONTROLLER 0x8 @@ -70,7 +79,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { */ #define MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO 0x7 #define MEGASAS_REQ_DESCRIPT_FLAGS_MFA 0x1 - +#define MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK 0x2 #define MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 1 #define MEGASAS_FP_CMD_LEN 16 @@ -82,7 +91,9 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { */ struct RAID_CONTEXT { - u16 resvd0; + u8 Type:4; + u8 nseg:4; + u8 resvd0; u16 timeoutValue; u8 regLockFlags; u8 resvd1; @@ -527,7 +538,7 @@ struct MR_LD_RAID { u8 ldState; u8 regTypeReqOnWrite; u8 modFactor; - u8 reserved2[1]; + u8 regTypeReqOnRead; u16 seqNum; struct { @@ -663,7 +674,7 @@ struct fusion_context { union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc; struct dma_pool *reply_frames_desc_pool; - u16 last_reply_idx; + u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION]; u32 reply_q_depth; u32 request_alloc_sz; |