From 058a8facfe1ee091b7188661937240fd0d950cf4 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:14:27 -0700 Subject: [SCSI] megaraid_sas: Continue booting immediately if FW in FAULT at driver load time Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_base.c | 20 +++++++++++--------- drivers/scsi/megaraid/megaraid_sas_fusion.c | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 776d0198866..9d5a14a2c5b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -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, @@ -2477,7 +2477,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); @@ -2617,7 +2617,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 +2639,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: /* @@ -3520,7 +3522,7 @@ 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 */ @@ -4357,7 +4359,7 @@ 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 */ diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index f13e7abd345..392b49d93b5 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -89,7 +89,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; @@ -2173,7 +2173,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; -- cgit v1.2.3 From 6bf579a326190d09d8c99316fefee7a6a892b891 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:14:33 -0700 Subject: [SCSI] megaraid_sas: Increase default cmds per lun to 256 Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 3948a00d81f..bc83eaad507 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -716,7 +716,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 * \ -- cgit v1.2.3 From d4a759a954072dcb0a0bbd64ec4bc5252182d032 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:14:39 -0700 Subject: [SCSI] megaraid_sas: Fix mismatch in megasas_reset_fusion() mutex lock-unlock Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 392b49d93b5..492ad42ff7a 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2057,8 +2057,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); -- cgit v1.2.3 From 8d960d4311dc8d5f623d64694744b1ac36332e3f Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:14:45 -0700 Subject: [SCSI] megaraid_sas: Remove some unnecessary code Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 492ad42ff7a..52f6a158477 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -139,11 +139,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; } @@ -590,7 +585,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; @@ -639,9 +633,6 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) 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; @@ -1612,7 +1603,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); @@ -1928,15 +1918,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); } -- cgit v1.2.3 From 6497b2475df330437d462c770ee9af0a271d88f9 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:14:50 -0700 Subject: [SCSI] megaraid_sas: Clear state change interrupts Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 52f6a158477..ec2e097f773 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -101,6 +101,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 */ @@ -1806,10 +1810,13 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) } /* 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)) { + 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; -- cgit v1.2.3 From 3f0e58bc8ff80e173660bdfcc514d8a5c4419764 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:14:59 -0700 Subject: [SCSI] megaraid_sas: Clear FUSION_IN_RESET before enabling interrupts Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index ec2e097f773..120499ade9a 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -2179,6 +2179,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; @@ -2240,6 +2242,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; } -- cgit v1.2.3 From 36807e6799dcd8f961137b74c7edce10c6fcb1d2 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:15:06 -0700 Subject: [SCSI] megaraid_sas: Add support for MegaRAID 9360/9380 12GB/s controllers Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.h | 2 + drivers/scsi/megaraid/megaraid_sas_base.c | 39 +++++++++--- drivers/scsi/megaraid/megaraid_sas_fp.c | 26 +++++--- drivers/scsi/megaraid/megaraid_sas_fusion.c | 96 +++++++++++++++++++++++------ drivers/scsi/megaraid/megaraid_sas_fusion.h | 16 ++++- 5 files changed, 139 insertions(+), 40 deletions(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index bc83eaad507..6b356255493 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -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 /* * ===================================== @@ -221,6 +222,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 }; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 9d5a14a2c5b..f2cf768c896 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -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 */ {} }; @@ -1583,7 +1585,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); @@ -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); @@ -2656,7 +2660,9 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) (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); @@ -2676,7 +2682,9 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) (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 @@ -2697,11 +2705,15 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) (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-> @@ -3498,6 +3510,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: @@ -3894,7 +3907,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; } @@ -4004,6 +4018,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; @@ -4096,7 +4111,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); @@ -4161,7 +4177,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) free_irq(instance->msi_flag ? instance->msixentry.vector : instance->pdev->irq, instance); 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); @@ -4368,6 +4385,7 @@ megasas_resume(struct pci_dev *pdev) 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)) { @@ -4501,6 +4519,7 @@ static void __devexit megasas_detach_one(struct pci_dev *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]) diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 5a5af1fe758..5255dd688ac 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -52,6 +52,7 @@ #include #include "megaraid_sas_fusion.h" +#include "megaraid_sas.h" #include #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 120499ade9a..ad6bd061a0f 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); @@ -1038,7 +1039,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; @@ -1061,14 +1064,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); @@ -1077,16 +1083,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; @@ -1095,13 +1099,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; @@ -1394,7 +1415,8 @@ 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; } @@ -1407,6 +1429,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 = @@ -1421,11 +1457,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 */ } @@ -1508,8 +1556,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); /* @@ -1863,6 +1913,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; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 82b577a72c8..9556c08490b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -44,6 +44,14 @@ #define HOST_DIAG_RESET_ADAPTER 0x4 #define MEGASAS_FUSION_MAX_RESET_TRIES 3 +/* 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 #define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f @@ -70,7 +78,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 +90,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 +537,7 @@ struct MR_LD_RAID { u8 ldState; u8 regTypeReqOnWrite; u8 modFactor; - u8 reserved2[1]; + u8 regTypeReqOnRead; u16 seqNum; struct { -- cgit v1.2.3 From c8e858fe72230dd2ad07abcbec7c9f201672a8b4 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:15:13 -0700 Subject: [SCSI] megaraid_sas: Add multiple MSI-X vector/multiple reply queue support Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.h | 11 +- drivers/scsi/megaraid/megaraid_sas_base.c | 156 +++++++++++++++++++++------- drivers/scsi/megaraid/megaraid_sas_fusion.c | 65 ++++++++---- drivers/scsi/megaraid/megaraid_sas_fusion.h | 3 +- 4 files changed, 176 insertions(+), 59 deletions(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 6b356255493..9ffb92daa58 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -757,6 +757,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 @@ -1278,6 +1279,11 @@ struct megasas_aen_event { struct megasas_instance *instance; }; +struct megasas_irq_context { + struct megasas_instance *instance; + u32 MSIxIndex; +}; + struct megasas_instance { u32 *producer; @@ -1351,8 +1357,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 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); } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index ad6bd061a0f..bfd87fab39a 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -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; @@ -633,7 +634,9 @@ 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); @@ -877,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; @@ -929,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 @@ -1421,6 +1426,12 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, 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); @@ -1691,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; @@ -1711,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; @@ -1784,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++; @@ -1813,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; @@ -1831,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); @@ -1841,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); } @@ -1850,10 +1870,11 @@ 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; @@ -1865,7 +1886,7 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) 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( @@ -2081,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; } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 9556c08490b..088c9f91da9 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -43,6 +43,7 @@ #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 @@ -673,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; -- cgit v1.2.3 From e5f93a36f72c9817b989f573f7140e3dfbce0f49 Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:15:19 -0700 Subject: [SCSI] megaraid_sas: Add driver workaround for PERC5/1068 kdump kernel panic The following patch for megaraid_sas adds a driver workaround for PERC5/1068 based controller FW that keeps a command from the main kernel that the driver cannot cancel which was causing a kernel panic in shutdown of the kdump kernel. Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.h | 1 + drivers/scsi/megaraid/megaraid_sas_base.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 9ffb92daa58..7375fde2ab4 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -139,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 diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index ec09d5c2ed9..de2f47c439c 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -215,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); @@ -2165,7 +2169,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: @@ -2934,6 +2947,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; -- cgit v1.2.3 From 8d6f5cea12e5eebdaca94b3a3a4bd4f12e83d85d Mon Sep 17 00:00:00 2001 From: adam radford Date: Sat, 8 Oct 2011 18:15:24 -0700 Subject: [SCSI] megaraid_sas: Changelog and version update The following patch for megaraid_sas updates the ChangeLog.megaraid_sas file and updates the driver version. Signed-off-by: Adam Radford Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas.h | 6 +++--- drivers/scsi/megaraid/megaraid_sas_base.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 7375fde2ab4..dd94c7d574f 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 diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index de2f47c439c..8d587cb73cb 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 -- cgit v1.2.3 From f575c5d3ebdca3b0482847d8fcba971767754a9e Mon Sep 17 00:00:00 2001 From: adam radford Date: Thu, 13 Oct 2011 16:01:12 -0700 Subject: [SCSI] megaraid_sas: Fix instance access in megasas_reset_timer The following patch for megaraid_sas will fix a potential bad pointer access in megasas_reset_timer(), when a MegaRAID 9265/9285 or 9360/9380 gets a timeout. megasas_build_io_fusion() sets SCp.ptr to be a struct megasas_cmd_fusion *, but then megasas_reset_timer() was casting SCp.ptr to be a struct megasas_cmd *, then trying to access cmd->instance, which is invalid. Just loading instance from scmd->device->host->hostdata in megasas_reset_timer() fixes the issue. Signed-off-by: Adam Radford Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/scsi/megaraid') diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 8d587cb73cb..29a994f9c4f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1914,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; @@ -1923,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); -- cgit v1.2.3