scsi: megaraid_sas: Resize MFA frame used for IOC INIT to 4k
authorShivasharan S <shivasharan.srikanteshwara@broadcom.com>
Thu, 19 Oct 2017 09:49:01 +0000 (02:49 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 25 Oct 2017 08:55:29 +0000 (04:55 -0400)
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>
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/megaraid/megaraid_sas_fusion.h

index 277fd16..857bdbb 100644 (file)
@@ -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);
 
index 5b3f1db..549f86b 100644 (file)
@@ -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;
 
 };