diff options
author | Shivasharan S <shivasharan.srikanteshwara@broadcom.com> | 2017-10-19 12:49:01 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2017-10-25 11:55:29 +0300 |
commit | b9637d14dc00d91cef0068cde1f9a8959b051028 (patch) | |
tree | e029c06e890fd56731873ef87d9bd4844daa04c7 /drivers/scsi/megaraid | |
parent | b99fc20281968b24ef8e3ab56cc5ba78c14b2a24 (diff) | |
download | linux-b9637d14dc00d91cef0068cde1f9a8959b051028.tar.xz |
scsi: megaraid_sas: Resize MFA frame used for IOC INIT to 4k
Older firmware version unconditionally pulls 4k frame for IOC INIT MFA
frame. But driver allocates 1k or 4k max_chain_frame_sz based on FW
capability. During boot time, this results in DMA read errors.
Workaround fix in driver by allocating separate ioc_init frame of 4k
size to support older firmware.
Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Cc: stable@vger.kernel.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/megaraid')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.c | 65 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.h | 2 |
2 files changed, 58 insertions, 9 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 277fd16305ee..857bdbb0f79d 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -780,13 +780,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) ioc_init_handle = fusion->ioc_init_request_phys; IOCInitMessage = fusion->ioc_init_request; - cmd = megasas_get_cmd(instance); - - if (!cmd) { - dev_err(&instance->pdev->dev, "Could not allocate cmd for INIT Frame\n"); - ret = 1; - goto fail_get_cmd; - } + cmd = fusion->ioc_init_cmd; scratch_pad_2 = readl (&instance->reg_set->outbound_scratch_pad_2); @@ -918,8 +912,6 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) ret = 0; fail_fw_init: - megasas_return_cmd(instance, cmd); -fail_get_cmd: dev_err(&instance->pdev->dev, "Init cmd return status %s for SCSI host %d\n", ret ? "FAILED" : "SUCCESS", instance->host->host_no); @@ -1333,6 +1325,56 @@ ld_drv_map_alloc_fail: return -ENOMEM; } +static int megasas_alloc_ioc_init_frame(struct megasas_instance *instance) +{ + struct fusion_context *fusion; + struct megasas_cmd *cmd; + + fusion = instance->ctrl_context; + + cmd = kmalloc(sizeof(struct megasas_cmd), GFP_KERNEL); + + if (!cmd) { + dev_err(&instance->pdev->dev, "Failed from func: %s line: %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + cmd->frame = dma_alloc_coherent(&instance->pdev->dev, + IOC_INIT_FRAME_SIZE, + &cmd->frame_phys_addr, GFP_KERNEL); + + if (!cmd->frame) { + dev_err(&instance->pdev->dev, "Failed from func: %s line: %d\n", + __func__, __LINE__); + kfree(cmd); + return -ENOMEM; + } + + fusion->ioc_init_cmd = cmd; + return 0; +} + +/** + * megasas_free_ioc_init_cmd - Free IOC INIT command frame + * @instance: Adapter soft state + */ +static inline void megasas_free_ioc_init_cmd(struct megasas_instance *instance) +{ + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + + if (fusion->ioc_init_cmd && fusion->ioc_init_cmd->frame) + dma_free_coherent(&instance->pdev->dev, + IOC_INIT_FRAME_SIZE, + fusion->ioc_init_cmd->frame, + fusion->ioc_init_cmd->frame_phys_addr); + + if (fusion->ioc_init_cmd) + kfree(fusion->ioc_init_cmd); +} + /** * megasas_init_adapter_fusion - Initializes the FW * @instance: Adapter soft state @@ -1428,6 +1470,9 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) MEGASAS_FUSION_IOCTL_CMDS); sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS); + if (megasas_alloc_ioc_init_frame(instance)) + return 1; + /* * Allocate memory for descriptors * Create a pool of commands @@ -1465,6 +1510,7 @@ fail_ioc_init: fail_alloc_cmds: megasas_free_cmds(instance); fail_alloc_mfi_cmds: + megasas_free_ioc_init_cmd(instance); return 1; } @@ -3383,6 +3429,7 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance, void megasas_release_fusion(struct megasas_instance *instance) { + megasas_free_ioc_init_cmd(instance); megasas_free_cmds(instance); megasas_free_cmds_fusion(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 5b3f1dba1ab2..549f86b2e871 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -103,6 +103,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define THRESHOLD_REPLY_COUNT 50 #define RAID_1_PEER_CMDS 2 #define JBOD_MAPS_COUNT 2 +#define IOC_INIT_FRAME_SIZE 4096 /* * Raid Context structure which describes MegaRAID specific IO Parameters @@ -1317,6 +1318,7 @@ struct fusion_context { struct LD_STREAM_DETECT **stream_detect_by_ld; dma_addr_t ioc_init_request_phys; struct MPI2_IOC_INIT_REQUEST *ioc_init_request; + struct megasas_cmd *ioc_init_cmd; }; |