diff mbox

[07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support

Message ID 1450445228-26571-8-git-send-email-Sumit.Saxena@avagotech.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

Sumit Saxena Dec. 18, 2015, 1:27 p.m. UTC
This patch will create reply queue pool for each MSI-x index and will provide array of all reply queue base address
instead of single base address of legacy mode. Using this new interface Driver can support higher Queue depth allocating
more reply queue as scattered DMA pool. 

If array mode is not supported driver will fall back to legacy method of allocation reply pool. 
This method fall back controller queue depth to 1K max. To enable more than 1K QD, driver expect FW to support Array mode 
and scratch_pad3 should provide new queue depth value.

Using this method, Firmware should not allow downgrade (OFU) if latest driver and latest FW report 4K QD and Array mode reply queue.
This type of FW upgrade may cause firmware fault and it should not be supported. Upgrade of FW will work, 
but queue depth of the controller will be unchanged until reboot/driver reload.

Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
---
 drivers/scsi/megaraid/megaraid_sas.h        |    6 +-
 drivers/scsi/megaraid/megaraid_sas_base.c   |    9 +
 drivers/scsi/megaraid/megaraid_sas_fusion.c |  543 +++++++++++++++------------
 drivers/scsi/megaraid/megaraid_sas_fusion.h |   12 +-
 4 files changed, 330 insertions(+), 240 deletions(-)

Comments

kernel test robot Dec. 18, 2015, 2:49 p.m. UTC | #1
Hi Sumit,

[auto build test WARNING on scsi/for-next]
[also build test WARNING on v4.4-rc5 next-20151218]

url:    https://github.com/0day-ci/linux/commits/Sumit-Saxena/megaraid_sas-Do-not-allow-PCI-access-during-OCR/20151218-213231
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/scsi/megaraid/megaraid_sas_fusion.c:331:20-27: WARNING: kzalloc should be used for fusion -> cmd_list, instead of kmalloc/memset
>> drivers/scsi/megaraid/megaraid_sas_fusion.c:342:24-31: WARNING: kzalloc should be used for fusion -> cmd_list [ i ], instead of kmalloc/memset

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tomas Henzl Jan. 14, 2016, 5:38 p.m. UTC | #2
On 18.12.2015 14:27, Sumit Saxena wrote:
> This patch will create reply queue pool for each MSI-x index and will provide array of all reply queue base address
> instead of single base address of legacy mode. Using this new interface Driver can support higher Queue depth allocating
> more reply queue as scattered DMA pool. 
>
> If array mode is not supported driver will fall back to legacy method of allocation reply pool. 
> This method fall back controller queue depth to 1K max. To enable more than 1K QD, driver expect FW to support Array mode 
> and scratch_pad3 should provide new queue depth value.
>
> Using this method, Firmware should not allow downgrade (OFU) if latest driver and latest FW report 4K QD and Array mode reply queue.
> This type of FW upgrade may cause firmware fault and it should not be supported. Upgrade of FW will work, 
> but queue depth of the controller will be unchanged until reboot/driver reload.
>
> Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> ---
>  drivers/scsi/megaraid/megaraid_sas.h        |    6 +-
>  drivers/scsi/megaraid/megaraid_sas_base.c   |    9 +
>  drivers/scsi/megaraid/megaraid_sas_fusion.c |  543 +++++++++++++++------------
>  drivers/scsi/megaraid/megaraid_sas_fusion.h |   12 +-
>  4 files changed, 330 insertions(+), 240 deletions(-)
>
> diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
> index 01135be..c539516 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.h
> +++ b/drivers/scsi/megaraid/megaraid_sas.h
> @@ -152,6 +152,7 @@
>  #define MFI_RESET_FLAGS				MFI_INIT_READY| \
>  						MFI_INIT_MFIMODE| \
>  						MFI_INIT_ABORT
> +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE    (0x01)
>  
>  /*
>   * MFI frame flags
> @@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION {
>  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET          0X003FC000
>  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
>  #define MR_MAX_MSIX_REG_ARRAY                   16
> +#define MR_RDPQ_MODE_OFFSET			0X00800000
>  /*
>  * register set for both 1068 and 1078 controllers
>  * structure extended for 1078 registers
> @@ -1455,8 +1457,9 @@ struct megasas_register_set {
>  
>  	u32 	outbound_scratch_pad ;		/*00B0h*/
>  	u32	outbound_scratch_pad_2;         /*00B4h*/
> +	u32	outbound_scratch_pad_3;         /*00B8h*/
>  
> -	u32	reserved_4[2];			/*00B8h*/
> +	u32	reserved_4;			/*00BCh*/
>  
>  	u32 	inbound_low_queue_port ;	/*00C0h*/
>  
> @@ -2117,6 +2120,7 @@ struct megasas_instance {
>  	u8 mask_interrupts;
>  	u16 max_chain_frame_sz;
>  	u8 is_imr;
> +	u8 is_rdpq;
>  	bool dev_handle;
>  };
>  struct MR_LD_VF_MAP {
> diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
> index df93fa1..a3b63fa 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> @@ -92,6 +92,10 @@ int smp_affinity_enable = 1;
>  module_param(smp_affinity_enable, int, S_IRUGO);
>  MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
>  
> +int rdpq_enable = 1;
> +module_param(rdpq_enable, int, S_IRUGO);
> +MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)");

Is it enabled or disabled by default (-> int rdpq_enable = 1;) ? also fix 'disbale'

> +
>  MODULE_LICENSE("GPL");
>  MODULE_VERSION(MEGASAS_VERSION);
>  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> @@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
>  				instance->msix_vectors = ((scratch_pad_2
>  					& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
>  					>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
> +				if (rdpq_enable)
> +					instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
> +								1 : 0;
>  				fw_msix_count = instance->msix_vectors;
>  				/* Save 1-15 reply post index address to local memory
>  				 * Index 0 is already saved from reg offset
> @@ -5117,6 +5124,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
>  	dev_info(&instance->pdev->dev,
>  		"current msix/online cpus\t: (%d/%d)\n",
>  		instance->msix_vectors, (unsigned int)num_online_cpus());
> +	dev_info(&instance->pdev->dev,
> +		"firmware supports rdpq mode\t: (%d)\n", instance->is_rdpq);

just a nit, but is_rdpq depends also on rdpq_enable, so the text is not precise

>  
>  	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
>  		(unsigned long)instance);
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> index e8730ef..aca0cd3 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> @@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance *instance,
>  			 void *fn, unsigned long interval);
>  extern struct megasas_mgmt_info megasas_mgmt_info;
>  extern int resetwaittime;
> +static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
> +static void megasas_free_reply_fusion(struct megasas_instance *instance);
>  
>  
>  
> @@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
>  #endif
>  }
>  
> -
>  /**
> - * megasas_teardown_frame_pool_fusion -	Destroy the cmd frame DMA pool
> - * @instance:				Adapter soft state
> + * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
> + * @instance:		Adapter soft state
>   */
> -static void megasas_teardown_frame_pool_fusion(
> -	struct megasas_instance *instance)
> +void
> +megasas_free_cmds_fusion(struct megasas_instance *instance)
>  {
>  	int i;
>  	struct fusion_context *fusion = instance->ctrl_context;
> -
> -	u16 max_cmd = instance->max_fw_cmds;
> -
>  	struct megasas_cmd_fusion *cmd;
>  
> -	if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
> -		dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, "
> -		       "sense pool : %p\n", fusion->sg_dma_pool,
> -		       fusion->sense_dma_pool);
> -		return;
> -	}
> -
> -	/*
> -	 * Return all frames to pool
> -	 */
> -	for (i = 0; i < max_cmd; i++) {
> -
> +	/* SG, Sense */
> +	for (i = 0; i < instance->max_fw_cmds; i++) {
>  		cmd = fusion->cmd_list[i];

cmd might be NULL here, add a test please

> -
>  		if (cmd->sg_frame)
>  			pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
> -				      cmd->sg_frame_phys_addr);
> -
> +			      cmd->sg_frame_phys_addr);
>  		if (cmd->sense)
>  			pci_pool_free(fusion->sense_dma_pool, cmd->sense,
> -				      cmd->sense_phys_addr);
> +			      cmd->sense_phys_addr);
>  	}
>  
> -	/*
> -	 * Now destroy the pool itself
> -	 */
> -	pci_pool_destroy(fusion->sg_dma_pool);
> -	pci_pool_destroy(fusion->sense_dma_pool);
> -
> -	fusion->sg_dma_pool = NULL;
> -	fusion->sense_dma_pool = NULL;
> -}
> -
> -/**
> - * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
> - * @instance:		Adapter soft state
> - */
> -void
> -megasas_free_cmds_fusion(struct megasas_instance *instance)
> -{
> -	int i;
> -	struct fusion_context *fusion = instance->ctrl_context;
> -
> -	u32 max_cmds, req_sz, reply_sz, io_frames_sz;
> -
> +	if (fusion->sg_dma_pool) {
> +		pci_pool_destroy(fusion->sg_dma_pool);
> +		fusion->sg_dma_pool = NULL;
> +	}
> +	if (fusion->sense_dma_pool) {
> +		pci_pool_destroy(fusion->sense_dma_pool);
> +		fusion->sense_dma_pool = NULL;

If this is needed (fusion->sense_dma_pool = NULL;), why don't we need
it few lines below for example for fusion->io_request_frames_pool ?
(there should be some consistency here)
 

> +	}
>  
> -	req_sz = fusion->request_alloc_sz;
> -	reply_sz = fusion->reply_alloc_sz;
> -	io_frames_sz = fusion->io_frames_alloc_sz;
>  
> -	max_cmds = instance->max_fw_cmds;
> +	/* Reply Frame, Desc*/
> +	if (instance->is_rdpq)
> +		megasas_free_rdpq_fusion(instance);
> +	else
> +		megasas_free_reply_fusion(instance);
>  
> -	/* Free descriptors and request Frames memory */
> +	/* Request Frame, Desc*/
>  	if (fusion->req_frames_desc)
> -		dma_free_coherent(&instance->pdev->dev, req_sz,
> -				  fusion->req_frames_desc,
> -				  fusion->req_frames_desc_phys);
> -
> -	if (fusion->reply_frames_desc) {
> -		pci_pool_free(fusion->reply_frames_desc_pool,
> -			      fusion->reply_frames_desc,
> -			      fusion->reply_frames_desc_phys);
> -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> -	}
> -
> -	if (fusion->io_request_frames) {
> +		dma_free_coherent(&instance->pdev->dev,
> +			fusion->request_alloc_sz, fusion->req_frames_desc,
> +			fusion->req_frames_desc_phys);
> +	if (fusion->io_request_frames)
>  		pci_pool_free(fusion->io_request_frames_pool,
> -			      fusion->io_request_frames,
> -			      fusion->io_request_frames_phys);
> +			fusion->io_request_frames,
> +			fusion->io_request_frames_phys);
> +	if (fusion->io_request_frames_pool)
>  		pci_pool_destroy(fusion->io_request_frames_pool);
> -	}
>  
> -	/* Free the Fusion frame pool */
> -	megasas_teardown_frame_pool_fusion(instance);
>  
> -	/* Free all the commands in the cmd_list */
> -	for (i = 0; i < max_cmds; i++)
> +	/* cmd_list */
> +	for (i = 0; i < instance->max_fw_cmds; i++)
>  		kfree(fusion->cmd_list[i]);
>  
> -	/* Free the cmd_list buffer itself */
>  	kfree(fusion->cmd_list);
>  	fusion->cmd_list = NULL;

It is a good idea to set (fusion->cmd_list = NULL;), but a test
to the kfree should be added  

> -
>  }
>  
>  /**
> - * megasas_create_frame_pool_fusion -	Creates DMA pool for cmd frames
> + * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd frames
>   * @instance:			Adapter soft state
>   *
>   */
> -static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
> +static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
>  {
>  	int i;
>  	u32 max_cmd;
> @@ -321,186 +282,299 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
>  	max_cmd = instance->max_fw_cmds;
>  
>  
> -	/*
> -	 * Use DMA pool facility provided by PCI layer
> -	 */
> -
> -	fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev,
> -						instance->max_chain_frame_sz,
> -						4, 0);
> -	if (!fusion->sg_dma_pool) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
> -		return -ENOMEM;
> -	}
> -	fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
> -						 instance->pdev,
> -						 SCSI_SENSE_BUFFERSIZE, 64, 0);
> +	fusion->sg_dma_pool =
> +			pci_pool_create("mr_sg", instance->pdev,
> +				instance->max_chain_frame_sz, 4, 0);
> +	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
> +	fusion->sense_dma_pool =
> +			pci_pool_create("mr_sense", instance->pdev,
> +				SCSI_SENSE_BUFFERSIZE, 64, 0);
>  
> -	if (!fusion->sense_dma_pool) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n");
> -		pci_pool_destroy(fusion->sg_dma_pool);
> -		fusion->sg_dma_pool = NULL;
> -		return -ENOMEM;
> -	}
> +	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool)
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);

Allocation failed - I don't think we can ignore it.

>  
>  	/*
>  	 * Allocate and attach a frame to each of the commands in cmd_list
>  	 */
>  	for (i = 0; i < max_cmd; i++) {
> -
>  		cmd = fusion->cmd_list[i];
> -
>  		cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
> -					       GFP_KERNEL,
> -					       &cmd->sg_frame_phys_addr);
> +					GFP_KERNEL, &cmd->sg_frame_phys_addr);
>  
>  		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
> -					    GFP_KERNEL, &cmd->sense_phys_addr);
> -		/*
> -		 * megasas_teardown_frame_pool_fusion() takes care of freeing
> -		 * whatever has been allocated
> -		 */
> +					GFP_KERNEL, &cmd->sense_phys_addr);
>  		if (!cmd->sg_frame || !cmd->sense) {
> -			dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n");
> -			megasas_teardown_frame_pool_fusion(instance);
> +			dev_err(&instance->pdev->dev,
> +				"Failed from %s %d\n",  __func__, __LINE__);
>  			return -ENOMEM;
>  		}
>  	}
>  	return 0;
>  }
>  
> -/**
> - * megasas_alloc_cmds_fusion -	Allocates the command packets
> - * @instance:		Adapter soft state
> - *
> - *
> - * Each frame has a 32-bit field called context. This context is used to get
> - * back the megasas_cmd_fusion from the frame when a frame gets completed
> - * In this driver, the 32 bit values are the indices into an array cmd_list.
> - * This array is used only to look up the megasas_cmd_fusion given the context.
> - * The free commands themselves are maintained in a linked list called cmd_pool.
> - *
> - * cmds are formed in the io_request and sg_frame members of the
> - * megasas_cmd_fusion. The context field is used to get a request descriptor
> - * and is used as SMID of the cmd.
> - * SMID value range is from 1 to max_fw_cmds.
> - */
>  int
> -megasas_alloc_cmds_fusion(struct megasas_instance *instance)
> +megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
>  {
> -	int i, j, count;
> -	u32 max_cmd, io_frames_sz;
> +	u32 max_cmd, i;
>  	struct fusion_context *fusion;
> -	struct megasas_cmd_fusion *cmd;
> -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> -	u32 offset;
> -	dma_addr_t io_req_base_phys;
> -	u8 *io_req_base;
>  
>  	fusion = instance->ctrl_context;
>  
>  	max_cmd = instance->max_fw_cmds;
>  
> +	/*
> +	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
> +	 * Allocate the dynamic array first and then allocate individual
> +	 * commands.
> +	 */
> +	fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
> +						GFP_KERNEL);
> +	if (!fusion->cmd_list) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
> +	}
> +	memset(fusion->cmd_list, 0,
> +		sizeof(struct megasas_cmd_fusion *) * max_cmd);
> +
> +	for (i = 0; i < max_cmd; i++) {
> +		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
> +					      GFP_KERNEL);

kzalloc here and there, as the kbuild script already wrote

> +		if (!fusion->cmd_list[i]) {
> +			dev_err(&instance->pdev->dev,
> +				"Failed from %s %d\n",  __func__, __LINE__);
> +			return -ENOMEM;
> +		}
> +		memset(fusion->cmd_list[i], 0, sizeof(struct megasas_cmd_fusion));
> +	}
> +	return 0;
> +}
> +int
> +megasas_alloc_request_fusion(struct megasas_instance *instance)
> +{
> +	struct fusion_context *fusion;
> +
> +	fusion = instance->ctrl_context;
> +
>  	fusion->req_frames_desc =
>  		dma_alloc_coherent(&instance->pdev->dev,
> -				   fusion->request_alloc_sz,
> -				   &fusion->req_frames_desc_phys, GFP_KERNEL);
> -
> +			fusion->request_alloc_sz,
> +			&fusion->req_frames_desc_phys, GFP_KERNEL);
>  	if (!fusion->req_frames_desc) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "request_frames\n");
> -		goto fail_req_desc;
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
> +	}
> +
> +	fusion->io_request_frames_pool =
> +			pci_pool_create("mr_ioreq", instance->pdev,
> +				fusion->io_frames_alloc_sz, 16, 0);

Why do you need a pool, you just allocate once a single region, or not?
Please turn it into a dma_alloc_coherent.

> +
> +	if (!fusion->io_request_frames_pool) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
> +	}
> +
> +	fusion->io_request_frames =
> +			pci_pool_alloc(fusion->io_request_frames_pool,
> +				GFP_KERNEL, &fusion->io_request_frames_phys);
> +	if (!fusion->io_request_frames) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
> +	return 0;
> +}
> +
> +int
> +megasas_alloc_reply_fusion(struct megasas_instance *instance)
> +{
> +	int i, count;
> +	struct fusion_context *fusion;
> +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> +	fusion = instance->ctrl_context;
>  
>  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
>  	fusion->reply_frames_desc_pool =
> -		pci_pool_create("reply_frames pool", instance->pdev,
> +			pci_pool_create("mr_reply", instance->pdev,
>  				fusion->reply_alloc_sz * count, 16, 0);
>  
>  	if (!fusion->reply_frames_desc_pool) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "reply_frame pool\n");
> -		goto fail_reply_desc;
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}

Same here, I could understand it if the code were merged with megasas_alloc_rdpq_fusion
but it is not. Why a pool?

>  
> -	fusion->reply_frames_desc =
> -		pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
> -			       &fusion->reply_frames_desc_phys);
> -	if (!fusion->reply_frames_desc) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "reply_frame pool\n");
> -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> -		goto fail_reply_desc;
> +	fusion->reply_frames_desc[0] =
> +		pci_pool_alloc(fusion->reply_frames_desc_pool,
> +			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
> +	if (!fusion->reply_frames_desc[0]) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
> -
> -	reply_desc = fusion->reply_frames_desc;
> +	reply_desc = fusion->reply_frames_desc[0];
>  	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
> -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> +		reply_desc->Words = ULLONG_MAX;

The megasas_reset_reply_desc function seems to be used for this kind of resetting,
could it be used here ? (and in megasas_alloc_rdpq_fusion)
There you also kept the cpu_to_le64(..) that doesn't matter,
but again for consistency...

>  
> -	io_frames_sz = fusion->io_frames_alloc_sz;
> +	/* This is not a rdpq mode, but driver still populate
> +	 * reply_frame_desc array to use same msix index in ISR path.
> +	 */
> +	for (i = 0; i < (count - 1); i++)
> +		fusion->reply_frames_desc[i + 1] =
> +			fusion->reply_frames_desc[i] +
> +			(fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
>  
> -	fusion->io_request_frames_pool =
> -		pci_pool_create("io_request_frames pool", instance->pdev,
> -				fusion->io_frames_alloc_sz, 16, 0);
> +	return 0;
> +}
>  
> -	if (!fusion->io_request_frames_pool) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "io_request_frame pool\n");
> -		goto fail_io_frames;
> +int
> +megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
> +{
> +	int i, j, count;
> +	struct fusion_context *fusion;
> +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> +
> +	fusion = instance->ctrl_context;
> +
> +	fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
> +				sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,

is dma_alloc_coherent possible here?

> +				&fusion->rdpq_phys);
> +	if (!fusion->rdpq_virt) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
>  
> -	fusion->io_request_frames =
> -		pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
> -			       &fusion->io_request_frames_phys);
> -	if (!fusion->io_request_frames) {
> -		dev_err(&instance->pdev->dev, "Could not allocate memory for "
> -		       "io_request_frames frames\n");
> -		pci_pool_destroy(fusion->io_request_frames_pool);
> -		goto fail_io_frames;
> +	memset(fusion->rdpq_virt, 0,
> +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
> +	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> +	fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
> +							 instance->pdev, fusion->reply_alloc_sz, 16, 0);
> +
> +	if (!fusion->reply_frames_desc_pool) {
> +		dev_err(&instance->pdev->dev,
> +			"Failed from %s %d\n",  __func__, __LINE__);
> +		return -ENOMEM;
>  	}
>  
> -	/*
> -	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
> -	 * Allocate the dynamic array first and then allocate individual
> -	 * commands.
> -	 */
> -	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
> -				   * max_cmd, GFP_KERNEL);
> +	for (i = 0; i < count; i++) {
> +		fusion->reply_frames_desc[i] =
> +				pci_pool_alloc(fusion->reply_frames_desc_pool,
> +					GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
> +		if (!fusion->reply_frames_desc[i]) {
> +			dev_err(&instance->pdev->dev,
> +				"Failed from %s %d\n",  __func__, __LINE__);
> +			return -ENOMEM;
> +		}
>  
> -	if (!fusion->cmd_list) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc "
> -		       "memory for cmd_list_fusion\n");
> -		goto fail_cmd_list;
> +		fusion->rdpq_virt[i].RDPQBaseAddress =
> +			fusion->reply_frames_desc_phys[i];
> +
> +		reply_desc = fusion->reply_frames_desc[i];
> +		for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
> +			reply_desc->Words = ULLONG_MAX;
>  	}
> +	return 0;
> +}
>  
> -	max_cmd = instance->max_fw_cmds;
> -	for (i = 0; i < max_cmd; i++) {
> -		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
> -					      GFP_KERNEL);
> -		if (!fusion->cmd_list[i]) {
> -			dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
> +static void
> +megasas_free_rdpq_fusion(struct megasas_instance *instance) {
>  
> -			for (j = 0; j < i; j++)
> -				kfree(fusion->cmd_list[j]);
> +	int i;
> +	struct fusion_context *fusion;
>  
> -			kfree(fusion->cmd_list);
> -			fusion->cmd_list = NULL;
> -			goto fail_cmd_list;
> -		}
> +	fusion = instance->ctrl_context;
> +
> +	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
> +		if (fusion->reply_frames_desc[i])
> +			pci_pool_free(fusion->reply_frames_desc_pool,
> +				fusion->reply_frames_desc[i],
> +				fusion->reply_frames_desc_phys[i]);
>  	}
>  
> -	/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
> -	io_req_base = fusion->io_request_frames +
> -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> -	io_req_base_phys = fusion->io_request_frames_phys +
> -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> +	if (fusion->reply_frames_desc_pool)
> +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> +
> +	if (fusion->rdpq_virt)
> +		pci_free_consistent(instance->pdev,
> +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
> +			fusion->rdpq_virt, fusion->rdpq_phys);
> +}
> +
> +static void
> +megasas_free_reply_fusion(struct megasas_instance *instance) {
> +
> +	struct fusion_context *fusion;
> +
> +	fusion = instance->ctrl_context;
> +
> +	if (fusion->reply_frames_desc[0])
> +		pci_pool_free(fusion->reply_frames_desc_pool,
> +			fusion->reply_frames_desc[0],
> +			fusion->reply_frames_desc_phys[0]);
> +
> +	if (fusion->reply_frames_desc_pool)
> +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> +
> +}
> +
> +
> +/**
> + * megasas_alloc_cmds_fusion -	Allocates the command packets
> + * @instance:		Adapter soft state
> + *
> + *
> + * Each frame has a 32-bit field called context. This context is used to get
> + * back the megasas_cmd_fusion from the frame when a frame gets completed
> + * In this driver, the 32 bit values are the indices into an array cmd_list.
> + * This array is used only to look up the megasas_cmd_fusion given the context.
> + * The free commands themselves are maintained in a linked list called cmd_pool.
> + *
> + * cmds are formed in the io_request and sg_frame members of the
> + * megasas_cmd_fusion. The context field is used to get a request descriptor
> + * and is used as SMID of the cmd.
> + * SMID value range is from 1 to max_fw_cmds.
> + */
> +int
> +megasas_alloc_cmds_fusion(struct megasas_instance *instance)
> +{
> +	int i;
> +	struct fusion_context *fusion;
> +	struct megasas_cmd_fusion *cmd;
> +	u32 offset;
> +	dma_addr_t io_req_base_phys;
> +	u8 *io_req_base;
> +
> +
> +	fusion = instance->ctrl_context;
> +
> +	if (megasas_alloc_cmdlist_fusion(instance))

We may need to call megasas_free_cmds_fusion here too
(to free fusion->cmd_list)

> +		return -ENOMEM;
> +
> +	if (megasas_alloc_request_fusion(instance))
> +		goto fail_exit;
> +
> +	if (instance->is_rdpq) {
> +		if (megasas_alloc_rdpq_fusion(instance))
> +			goto fail_exit;
> +	} else
> +		if (megasas_alloc_reply_fusion(instance))
> +			goto fail_exit;
> +
> +
> +	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
> +	io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> +	io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
>  
>  	/*
>  	 * Add all the commands to command pool (fusion->cmd_pool)
>  	 */
>  
>  	/* SMID 0 is reserved. Set SMID/index from 1 */
> -	for (i = 0; i < max_cmd; i++) {
> +	for (i = 0; i < instance->max_fw_cmds; i++) {
>  		cmd = fusion->cmd_list[i];
>  		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
>  		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));

That memset was already done in megasas_alloc_cmdlist_fusion

> @@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
>  		cmd->io_request_phys_addr = io_req_base_phys + offset;
>  	}/
>  
> -	/*
> -	 * Create a frame pool and assign one frame to each cmd
> -	 */
> -	if (megasas_create_frame_pool_fusion(instance)) {
> -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
> -		megasas_free_cmds_fusion(instance);
> -		goto fail_req_desc;
> -	}
> +	if (megasas_create_sg_sense_fusion(instance))
> +		goto fail_exit;
>  
>  	return 0;
>  
> -fail_cmd_list:
> -	pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
> -		      fusion->io_request_frames_phys);
> -	pci_pool_destroy(fusion->io_request_frames_pool);
> -fail_io_frames:
> -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> -			  fusion->reply_frames_desc,
> -			  fusion->reply_frames_desc_phys);
> -	pci_pool_free(fusion->reply_frames_desc_pool,
> -		      fusion->reply_frames_desc,
> -		      fusion->reply_frames_desc_phys);
> -	pci_pool_destroy(fusion->reply_frames_desc_pool);
> -
> -fail_reply_desc:
> -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> -			  fusion->req_frames_desc,
> -			  fusion->req_frames_desc_phys);
> -fail_req_desc:
> +fail_exit:
> +	megasas_free_cmds_fusion(instance);
>  	return -ENOMEM;
>  }
>  
> @@ -594,16 +646,17 @@ int
>  megasas_ioc_init_fusion(struct megasas_instance *instance)
>  {
>  	struct megasas_init_frame *init_frame;
> -	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
> +	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
>  	dma_addr_t	ioc_init_handle;
>  	struct megasas_cmd *cmd;
> -	u8 ret;
> +	u8 ret, cur_rdpq_mode;
>  	struct fusion_context *fusion;
>  	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
>  	int i;
>  	struct megasas_header *frame_hdr;
>  	const char *sys_info;
>  	MFI_CAPABILITIES *drv_ops;
> +	u32 scratch_pad_2;
>  
>  	fusion = instance->ctrl_context;
>  
> @@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
>  		goto fail_get_cmd;
>  	}
>  
> +	scratch_pad_2 = readl
> +		(&instance->reg_set->outbound_scratch_pad_2);
> +
> +	cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
> +
> +	if (instance->is_rdpq && !cur_rdpq_mode) {
> +		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
> +			" from RDPQ mode to non RDPQ mode\n");

How does this work ? is_rdpq is set in megasas_init_fw only when the fw
supports it, why do you test it here again ? I think I'm miss something.

Tomas

> +		ret = 1;
> +		goto fail_fw_init;
> +	}
> +
>  	IOCInitMessage =
>  	  dma_alloc_coherent(&instance->pdev->dev,
>  			     sizeof(struct MPI2_IOC_INIT_REQUEST),
> @@ -636,7 +701,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
>  	IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
>  
>  	IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
> -	IOCInitMessage->ReplyDescriptorPostQueueAddress	= cpu_to_le64(fusion->reply_frames_desc_phys);
> +	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
> +			cpu_to_le64(fusion->rdpq_phys) :
> +			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
> +	IOCInitMessage->MsgFlags = instance->is_rdpq ?
> +			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
>  	IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
>  	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
>  	init_frame = (struct megasas_init_frame *)cmd->frame;
> @@ -1087,7 +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
>  	 */
>  	instance->max_fw_cmds =
>  		instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
> -	instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
> +	dev_info(&instance->pdev->dev,
> +		"firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds);
> +	if (!instance->is_rdpq)
> +		instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
>  
>  	/*
>  	 * Reduce the max supported cmds by 1. This is to ensure that the
> @@ -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
>  	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
>  		return IRQ_HANDLED;
>  
> -	desc = fusion->reply_frames_desc;
> -	desc += ((MSIxIndex * fusion->reply_alloc_sz)/
> -		 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
> -		fusion->last_reply_idx[MSIxIndex];
> +	desc = fusion->reply_frames_desc[MSIxIndex] +
> +				fusion->last_reply_idx[MSIxIndex];
>  
>  	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
>  
> @@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
>  
>  		/* Get the next reply descriptor */
>  		if (!fusion->last_reply_idx[MSIxIndex])
> -			desc = fusion->reply_frames_desc +
> -				((MSIxIndex * fusion->reply_alloc_sz)/
> -				 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
> +			desc = fusion->reply_frames_desc[MSIxIndex];
>  		else
>  			desc++;
>  
> @@ -2688,17 +2756,18 @@ out:
>  
>  void  megasas_reset_reply_desc(struct megasas_instance *instance)
>  {
> -	int i, count;
> +	int i, j, count;
>  	struct fusion_context *fusion;
>  	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
>  
>  	fusion = instance->ctrl_context;
>  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> -	for (i = 0 ; i < count ; i++)
> +	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 * count; i++, reply_desc++)
> -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> +		reply_desc = fusion->reply_frames_desc[i];
> +		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
> +			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> +	}
>  }
>  
>  /*
> diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> index db0978d..80eaee2 100644
> --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> @@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
>  	struct MR_PD_CFG_SEQ seq[1];
>  } __packed;
>  
> +struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
> +	u64 RDPQBaseAddress;
> +	u32 Reserved1;
> +	u32 Reserved2;
> +};
> +
>  struct fusion_context {
>  	struct megasas_cmd_fusion **cmd_list;
>  	dma_addr_t req_frames_desc_phys;
> @@ -940,8 +946,8 @@ struct fusion_context {
>  	struct dma_pool *sg_dma_pool;
>  	struct dma_pool *sense_dma_pool;
>  
> -	dma_addr_t reply_frames_desc_phys;
> -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
> +	dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
> +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
>  	struct dma_pool *reply_frames_desc_pool;
>  
>  	u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
> @@ -951,6 +957,8 @@ struct fusion_context {
>  	u32 reply_alloc_sz;
>  	u32 io_frames_alloc_sz;
>  
> +	struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
> +	dma_addr_t rdpq_phys;
>  	u16	max_sge_in_main_msg;
>  	u16	max_sge_in_chain;
>  

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sumit Saxena Jan. 27, 2016, 6:15 p.m. UTC | #3
Tomas,
This reply was stuck in my outbox(was not sent). Just realized now this
when reworking on patches to accommodate your feedback. Apologies for late
reply.

Thanks,
Sumit

> -----Original Message-----
> From: Tomas Henzl [mailto:thenzl@redhat.com]
> Sent: Thursday, January 14, 2016 11:09 PM
> To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org;
> martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com
> Subject: Re: [PATCH 07/15] megaraid_sas: Reply Descriptor Post
Queue(RDPQ)
> support
>
> On 18.12.2015 14:27, Sumit Saxena wrote:
> > This patch will create reply queue pool for each MSI-x index and will
> > provide array of all reply queue base address instead of single base
> > address of legacy mode. Using this new interface Driver can support
higher
> Queue depth allocating more reply queue as scattered DMA pool.
> >
> > If array mode is not supported driver will fall back to legacy method
of
> allocation reply pool.
> > This method fall back controller queue depth to 1K max. To enable more
> > than 1K QD, driver expect FW to support Array mode and scratch_pad3
should
> provide new queue depth value.
> >
> > Using this method, Firmware should not allow downgrade (OFU) if latest
driver
> and latest FW report 4K QD and Array mode reply queue.
> > This type of FW upgrade may cause firmware fault and it should not be
> > supported. Upgrade of FW will work, but queue depth of the controller
will be
> unchanged until reboot/driver reload.
> >
> > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com>
> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
> > ---
> >  drivers/scsi/megaraid/megaraid_sas.h        |    6 +-
> >  drivers/scsi/megaraid/megaraid_sas_base.c   |    9 +
> >  drivers/scsi/megaraid/megaraid_sas_fusion.c |  543
+++++++++++++++--------
> ----
> >  drivers/scsi/megaraid/megaraid_sas_fusion.h |   12 +-
> >  4 files changed, 330 insertions(+), 240 deletions(-)
> >
> > diff --git a/drivers/scsi/megaraid/megaraid_sas.h
> > b/drivers/scsi/megaraid/megaraid_sas.h
> > index 01135be..c539516 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas.h
> > @@ -152,6 +152,7 @@
> >  #define MFI_RESET_FLAGS				MFI_INIT_READY| \
> >  						MFI_INIT_MFIMODE| \
> >  						MFI_INIT_ABORT
> > +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE    (0x01)
> >
> >  /*
> >   * MFI frame flags
> > @@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION {
> >  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET          0X003FC000
> >  #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
> >  #define MR_MAX_MSIX_REG_ARRAY                   16
> > +#define MR_RDPQ_MODE_OFFSET			0X00800000
> >  /*
> >  * register set for both 1068 and 1078 controllers
> >  * structure extended for 1078 registers @@ -1455,8 +1457,9 @@ struct
> > megasas_register_set {
> >
> >  	u32 	outbound_scratch_pad ;		/*00B0h*/
> >  	u32	outbound_scratch_pad_2;         /*00B4h*/
> > +	u32	outbound_scratch_pad_3;         /*00B8h*/
> >
> > -	u32	reserved_4[2];			/*00B8h*/
> > +	u32	reserved_4;			/*00BCh*/
> >
> >  	u32 	inbound_low_queue_port ;	/*00C0h*/
> >
> > @@ -2117,6 +2120,7 @@ struct megasas_instance {
> >  	u8 mask_interrupts;
> >  	u16 max_chain_frame_sz;
> >  	u8 is_imr;
> > +	u8 is_rdpq;
> >  	bool dev_handle;
> >  };
> >  struct MR_LD_VF_MAP {
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c
> > b/drivers/scsi/megaraid/megaraid_sas_base.c
> > index df93fa1..a3b63fa 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_base.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c
> > @@ -92,6 +92,10 @@ int smp_affinity_enable = 1;
> > module_param(smp_affinity_enable, int, S_IRUGO);
> > MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature
> > enable/disbale Default: enable(1)");
> >
> > +int rdpq_enable = 1;
> > +module_param(rdpq_enable, int, S_IRUGO);
> > +MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for
> > +large queue depth enable/disbale Default: disable(0)");
>
> Is it enabled or disabled by default (-> int rdpq_enable = 1;) ? also
fix 'disbale'

It's enabled by default. I will fix typo.
>
> > +
> >  MODULE_LICENSE("GPL");
> >  MODULE_VERSION(MEGASAS_VERSION);
> >  MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
> > @@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct
megasas_instance
> *instance)
> >  				instance->msix_vectors = ((scratch_pad_2
> >  					&
> MR_MAX_REPLY_QUEUES_EXT_OFFSET)
> >  					>>
> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
> > +				if (rdpq_enable)
> > +					instance->is_rdpq = (scratch_pad_2
&
> MR_RDPQ_MODE_OFFSET) ?
> > +								1 : 0;
> >  				fw_msix_count = instance->msix_vectors;
> >  				/* Save 1-15 reply post index address to
local
> memory
> >  				 * Index 0 is already saved from reg
offset @@
> -5117,6 +5124,8 @@
> > static int megasas_init_fw(struct megasas_instance *instance)
> >  	dev_info(&instance->pdev->dev,
> >  		"current msix/online cpus\t: (%d/%d)\n",
> >  		instance->msix_vectors, (unsigned int)num_online_cpus());
> > +	dev_info(&instance->pdev->dev,
> > +		"firmware supports rdpq mode\t: (%d)\n",
instance->is_rdpq);
>
> just a nit, but is_rdpq depends also on rdpq_enable, so the text is not
precise


I will modify text to reflect the correct information.
>
> >
> >  	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
> >  		(unsigned long)instance);
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > index e8730ef..aca0cd3 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
> > @@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance
> *instance,
> >  			 void *fn, unsigned long interval);  extern struct
> > megasas_mgmt_info megasas_mgmt_info;  extern int resetwaittime;
> > +static void megasas_free_rdpq_fusion(struct megasas_instance
> > +*instance); static void megasas_free_reply_fusion(struct
> > +megasas_instance *instance);
> >
> >
> >
> > @@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct
> megasas_instance
> > *instance,  #endif  }
> >
> > -
> >  /**
> > - * megasas_teardown_frame_pool_fusion -	Destroy the cmd frame DMA
> pool
> > - * @instance:				Adapter soft state
> > + * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
pool
> > + * @instance:		Adapter soft state
> >   */
> > -static void megasas_teardown_frame_pool_fusion(
> > -	struct megasas_instance *instance)
> > +void
> > +megasas_free_cmds_fusion(struct megasas_instance *instance)
> >  {
> >  	int i;
> >  	struct fusion_context *fusion = instance->ctrl_context;
> > -
> > -	u16 max_cmd = instance->max_fw_cmds;
> > -
> >  	struct megasas_cmd_fusion *cmd;
> >
> > -	if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
> > -		dev_err(&instance->pdev->dev, "dma pool is null. SG Pool
%p, "
> > -		       "sense pool : %p\n", fusion->sg_dma_pool,
> > -		       fusion->sense_dma_pool);
> > -		return;
> > -	}
> > -
> > -	/*
> > -	 * Return all frames to pool
> > -	 */
> > -	for (i = 0; i < max_cmd; i++) {
> > -
> > +	/* SG, Sense */
> > +	for (i = 0; i < instance->max_fw_cmds; i++) {
> >  		cmd = fusion->cmd_list[i];
>
> cmd might be NULL here, add a test please

Cmd cannot be NULL. If I am missing, do you see any instance where cmd
might be NULL?
>
> > -
> >  		if (cmd->sg_frame)
> >  			pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
> > -				      cmd->sg_frame_phys_addr);
> > -
> > +			      cmd->sg_frame_phys_addr);
> >  		if (cmd->sense)
> >  			pci_pool_free(fusion->sense_dma_pool, cmd->sense,
> > -				      cmd->sense_phys_addr);
> > +			      cmd->sense_phys_addr);
> >  	}
> >
> > -	/*
> > -	 * Now destroy the pool itself
> > -	 */
> > -	pci_pool_destroy(fusion->sg_dma_pool);
> > -	pci_pool_destroy(fusion->sense_dma_pool);
> > -
> > -	fusion->sg_dma_pool = NULL;
> > -	fusion->sense_dma_pool = NULL;
> > -}
> > -
> > -/**
> > - * megasas_free_cmds_fusion -	Free all the cmds in the free cmd
pool
> > - * @instance:		Adapter soft state
> > - */
> > -void
> > -megasas_free_cmds_fusion(struct megasas_instance *instance) -{
> > -	int i;
> > -	struct fusion_context *fusion = instance->ctrl_context;
> > -
> > -	u32 max_cmds, req_sz, reply_sz, io_frames_sz;
> > -
> > +	if (fusion->sg_dma_pool) {
> > +		pci_pool_destroy(fusion->sg_dma_pool);
> > +		fusion->sg_dma_pool = NULL;
> > +	}
> > +	if (fusion->sense_dma_pool) {
> > +		pci_pool_destroy(fusion->sense_dma_pool);
> > +		fusion->sense_dma_pool = NULL;
>
> If this is needed (fusion->sense_dma_pool = NULL;), why don't we need it
few
> lines below for example for fusion->io_request_frames_pool ?
> (there should be some consistency here)
>
Agree.. will add (fusion->io_request_frames_pool=NULL).
>
> > +	}
> >
> > -	req_sz = fusion->request_alloc_sz;
> > -	reply_sz = fusion->reply_alloc_sz;
> > -	io_frames_sz = fusion->io_frames_alloc_sz;
> >
> > -	max_cmds = instance->max_fw_cmds;
> > +	/* Reply Frame, Desc*/
> > +	if (instance->is_rdpq)
> > +		megasas_free_rdpq_fusion(instance);
> > +	else
> > +		megasas_free_reply_fusion(instance);
> >
> > -	/* Free descriptors and request Frames memory */
> > +	/* Request Frame, Desc*/
> >  	if (fusion->req_frames_desc)
> > -		dma_free_coherent(&instance->pdev->dev, req_sz,
> > -				  fusion->req_frames_desc,
> > -				  fusion->req_frames_desc_phys);
> > -
> > -	if (fusion->reply_frames_desc) {
> > -		pci_pool_free(fusion->reply_frames_desc_pool,
> > -			      fusion->reply_frames_desc,
> > -			      fusion->reply_frames_desc_phys);
> > -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > -	}
> > -
> > -	if (fusion->io_request_frames) {
> > +		dma_free_coherent(&instance->pdev->dev,
> > +			fusion->request_alloc_sz, fusion->req_frames_desc,
> > +			fusion->req_frames_desc_phys);
> > +	if (fusion->io_request_frames)
> >  		pci_pool_free(fusion->io_request_frames_pool,
> > -			      fusion->io_request_frames,
> > -			      fusion->io_request_frames_phys);
> > +			fusion->io_request_frames,
> > +			fusion->io_request_frames_phys);
> > +	if (fusion->io_request_frames_pool)
> >  		pci_pool_destroy(fusion->io_request_frames_pool);
> > -	}
> >
> > -	/* Free the Fusion frame pool */
> > -	megasas_teardown_frame_pool_fusion(instance);
> >
> > -	/* Free all the commands in the cmd_list */
> > -	for (i = 0; i < max_cmds; i++)
> > +	/* cmd_list */
> > +	for (i = 0; i < instance->max_fw_cmds; i++)
> >  		kfree(fusion->cmd_list[i]);
> >
> > -	/* Free the cmd_list buffer itself */
> >  	kfree(fusion->cmd_list);
> >  	fusion->cmd_list = NULL;
>
> It is a good idea to set (fusion->cmd_list = NULL;), but a test to the
kfree should
> be added
Kfree returns void. What test is needed here? Please clarify if you mean
something elase.
>
> > -
> >  }
> >
> >  /**
> > - * megasas_create_frame_pool_fusion -	Creates DMA pool for cmd
> frames
> > + * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd
frames
> >   * @instance:			Adapter soft state
> >   *
> >   */
> > -static int megasas_create_frame_pool_fusion(struct megasas_instance
> > *instance)
> > +static int megasas_create_sg_sense_fusion(struct megasas_instance
> > +*instance)
> >  {
> >  	int i;
> >  	u32 max_cmd;
> > @@ -321,186 +282,299 @@ static int
> megasas_create_frame_pool_fusion(struct megasas_instance *instance)
> >  	max_cmd = instance->max_fw_cmds;
> >
> >
> > -	/*
> > -	 * Use DMA pool facility provided by PCI layer
> > -	 */
> > -
> > -	fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance-
> >pdev,
> > -						instance-
> >max_chain_frame_sz,
> > -						4, 0);
> > -	if (!fusion->sg_dma_pool) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to
> setup request pool fusion\n");
> > -		return -ENOMEM;
> > -	}
> > -	fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
> > -						 instance->pdev,
> > -						 SCSI_SENSE_BUFFERSIZE,
64,
> 0);
> > +	fusion->sg_dma_pool =
> > +			pci_pool_create("mr_sg", instance->pdev,
> > +				instance->max_chain_frame_sz, 4, 0);
> > +	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
> > +	fusion->sense_dma_pool =
> > +			pci_pool_create("mr_sense", instance->pdev,
> > +				SCSI_SENSE_BUFFERSIZE, 64, 0);
> >
> > -	if (!fusion->sense_dma_pool) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to
> setup sense pool fusion\n");
> > -		pci_pool_destroy(fusion->sg_dma_pool);
> > -		fusion->sg_dma_pool = NULL;
> > -		return -ENOMEM;
> > -	}
> > +	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool)
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
>
> Allocation failed - I don't think we can ignore it.
Agreed..Will rectify this.
>
> >
> >  	/*
> >  	 * Allocate and attach a frame to each of the commands in cmd_list
> >  	 */
> >  	for (i = 0; i < max_cmd; i++) {
> > -
> >  		cmd = fusion->cmd_list[i];
> > -
> >  		cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
> > -					       GFP_KERNEL,
> > -					       &cmd->sg_frame_phys_addr);
> > +					GFP_KERNEL, &cmd-
> >sg_frame_phys_addr);
> >
> >  		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
> > -					    GFP_KERNEL, &cmd-
> >sense_phys_addr);
> > -		/*
> > -		 * megasas_teardown_frame_pool_fusion() takes care of
> freeing
> > -		 * whatever has been allocated
> > -		 */
> > +					GFP_KERNEL, &cmd-
> >sense_phys_addr);
> >  		if (!cmd->sg_frame || !cmd->sense) {
> > -			dev_printk(KERN_DEBUG, &instance->pdev->dev,
> "pci_pool_alloc failed\n");
> > -			megasas_teardown_frame_pool_fusion(instance);
> > +			dev_err(&instance->pdev->dev,
> > +				"Failed from %s %d\n",  __func__,
__LINE__);
> >  			return -ENOMEM;
> >  		}
> >  	}
> >  	return 0;
> >  }
> >
> > -/**
> > - * megasas_alloc_cmds_fusion -	Allocates the command packets
> > - * @instance:		Adapter soft state
> > - *
> > - *
> > - * Each frame has a 32-bit field called context. This context is used
> > to get
> > - * back the megasas_cmd_fusion from the frame when a frame gets
> > completed
> > - * In this driver, the 32 bit values are the indices into an array
cmd_list.
> > - * This array is used only to look up the megasas_cmd_fusion given
the
> context.
> > - * The free commands themselves are maintained in a linked list
called
> cmd_pool.
> > - *
> > - * cmds are formed in the io_request and sg_frame members of the
> > - * megasas_cmd_fusion. The context field is used to get a request
> > descriptor
> > - * and is used as SMID of the cmd.
> > - * SMID value range is from 1 to max_fw_cmds.
> > - */
> >  int
> > -megasas_alloc_cmds_fusion(struct megasas_instance *instance)
> > +megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
> >  {
> > -	int i, j, count;
> > -	u32 max_cmd, io_frames_sz;
> > +	u32 max_cmd, i;
> >  	struct fusion_context *fusion;
> > -	struct megasas_cmd_fusion *cmd;
> > -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> > -	u32 offset;
> > -	dma_addr_t io_req_base_phys;
> > -	u8 *io_req_base;
> >
> >  	fusion = instance->ctrl_context;
> >
> >  	max_cmd = instance->max_fw_cmds;
> >
> > +	/*
> > +	 * fusion->cmd_list is an array of struct megasas_cmd_fusion
pointers.
> > +	 * Allocate the dynamic array first and then allocate individual
> > +	 * commands.
> > +	 */
> > +	fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) *
> max_cmd,
> > +						GFP_KERNEL);
> > +	if (!fusion->cmd_list) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> > +	}
> > +	memset(fusion->cmd_list, 0,
> > +		sizeof(struct megasas_cmd_fusion *) * max_cmd);
> > +
> > +	for (i = 0; i < max_cmd; i++) {
> > +		fusion->cmd_list[i] = kmalloc(sizeof(struct
> megasas_cmd_fusion),
> > +					      GFP_KERNEL);
>
> kzalloc here and there, as the kbuild script already wrote
>
> > +		if (!fusion->cmd_list[i]) {
> > +			dev_err(&instance->pdev->dev,
> > +				"Failed from %s %d\n",  __func__,
__LINE__);
> > +			return -ENOMEM;
> > +		}
> > +		memset(fusion->cmd_list[i], 0, sizeof(struct
> megasas_cmd_fusion));
> > +	}
> > +	return 0;
> > +}
> > +int
> > +megasas_alloc_request_fusion(struct megasas_instance *instance) {
> > +	struct fusion_context *fusion;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> >  	fusion->req_frames_desc =
> >  		dma_alloc_coherent(&instance->pdev->dev,
> > -				   fusion->request_alloc_sz,
> > -				   &fusion->req_frames_desc_phys,
> GFP_KERNEL);
> > -
> > +			fusion->request_alloc_sz,
> > +			&fusion->req_frames_desc_phys, GFP_KERNEL);
> >  	if (!fusion->req_frames_desc) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "request_frames\n");
> > -		goto fail_req_desc;
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	fusion->io_request_frames_pool =
> > +			pci_pool_create("mr_ioreq", instance->pdev,
> > +				fusion->io_frames_alloc_sz, 16, 0);
>
> Why do you need a pool, you just allocate once a single region, or not?
> Please turn it into a dma_alloc_coherent.

There are some places where dma_alloc_coherent can be used instead of PCI
APIs. If you are OK with ignoring this for now,
I will be sending followup patch to address all such issues.
>
> > +
> > +	if (!fusion->io_request_frames_pool) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	fusion->io_request_frames =
> > +			pci_pool_alloc(fusion->io_request_frames_pool,
> > +				GFP_KERNEL, &fusion-
> >io_request_frames_phys);
> > +	if (!fusion->io_request_frames) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> > +	return 0;
> > +}
> > +
> > +int
> > +megasas_alloc_reply_fusion(struct megasas_instance *instance) {
> > +	int i, count;
> > +	struct fusion_context *fusion;
> > +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> > +	fusion = instance->ctrl_context;
> >
> >  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> >  	fusion->reply_frames_desc_pool =
> > -		pci_pool_create("reply_frames pool", instance->pdev,
> > +			pci_pool_create("mr_reply", instance->pdev,
> >  				fusion->reply_alloc_sz * count, 16, 0);
> >
> >  	if (!fusion->reply_frames_desc_pool) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "reply_frame pool\n");
> > -		goto fail_reply_desc;
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
>
> Same here, I could understand it if the code were merged with
> megasas_alloc_rdpq_fusion but it is not. Why a pool?
Same reason for this..
>
> >
> > -	fusion->reply_frames_desc =
> > -		pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
> > -			       &fusion->reply_frames_desc_phys);
> > -	if (!fusion->reply_frames_desc) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "reply_frame pool\n");
> > -		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > -		goto fail_reply_desc;
> > +	fusion->reply_frames_desc[0] =
> > +		pci_pool_alloc(fusion->reply_frames_desc_pool,
> > +			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
> > +	if (!fusion->reply_frames_desc[0]) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> > -
> > -	reply_desc = fusion->reply_frames_desc;
> > +	reply_desc = fusion->reply_frames_desc[0];
> >  	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
> > -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> > +		reply_desc->Words = ULLONG_MAX;
>
> The megasas_reset_reply_desc function seems to be used for this kind of
> resetting, could it be used here ? (and in megasas_alloc_rdpq_fusion)
There you
> also kept the cpu_to_le64(..) that doesn't matter, but again for
consistency...

I will take care of all this in next patchset.
>
> >
> > -	io_frames_sz = fusion->io_frames_alloc_sz;
> > +	/* This is not a rdpq mode, but driver still populate
> > +	 * reply_frame_desc array to use same msix index in ISR path.
> > +	 */
> > +	for (i = 0; i < (count - 1); i++)
> > +		fusion->reply_frames_desc[i + 1] =
> > +			fusion->reply_frames_desc[i] +
> > +			(fusion->reply_alloc_sz)/sizeof(union
> > +MPI2_REPLY_DESCRIPTORS_UNION);
> >
> > -	fusion->io_request_frames_pool =
> > -		pci_pool_create("io_request_frames pool", instance->pdev,
> > -				fusion->io_frames_alloc_sz, 16, 0);
> > +	return 0;
> > +}
> >
> > -	if (!fusion->io_request_frames_pool) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "io_request_frame pool\n");
> > -		goto fail_io_frames;
> > +int
> > +megasas_alloc_rdpq_fusion(struct megasas_instance *instance) {
> > +	int i, j, count;
> > +	struct fusion_context *fusion;
> > +	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
> > +				sizeof(struct
> MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
> > +MAX_MSIX_QUEUES_FUSION,
>
> is dma_alloc_coherent possible here?
>
> > +				&fusion->rdpq_phys);
> > +	if (!fusion->rdpq_virt) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> >
> > -	fusion->io_request_frames =
> > -		pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
> > -			       &fusion->io_request_frames_phys);
> > -	if (!fusion->io_request_frames) {
> > -		dev_err(&instance->pdev->dev, "Could not allocate memory
for
> "
> > -		       "io_request_frames frames\n");
> > -		pci_pool_destroy(fusion->io_request_frames_pool);
> > -		goto fail_io_frames;
> > +	memset(fusion->rdpq_virt, 0,
> > +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
> MAX_MSIX_QUEUES_FUSION);
> > +	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> > +	fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
> > +							 instance->pdev,
> fusion->reply_alloc_sz, 16, 0);
> > +
> > +	if (!fusion->reply_frames_desc_pool) {
> > +		dev_err(&instance->pdev->dev,
> > +			"Failed from %s %d\n",  __func__, __LINE__);
> > +		return -ENOMEM;
> >  	}
> >
> > -	/*
> > -	 * fusion->cmd_list is an array of struct megasas_cmd_fusion
pointers.
> > -	 * Allocate the dynamic array first and then allocate individual
> > -	 * commands.
> > -	 */
> > -	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
> > -				   * max_cmd, GFP_KERNEL);
> > +	for (i = 0; i < count; i++) {
> > +		fusion->reply_frames_desc[i] =
> > +				pci_pool_alloc(fusion-
> >reply_frames_desc_pool,
> > +					GFP_KERNEL, &fusion-
> >reply_frames_desc_phys[i]);
> > +		if (!fusion->reply_frames_desc[i]) {
> > +			dev_err(&instance->pdev->dev,
> > +				"Failed from %s %d\n",  __func__,
__LINE__);
> > +			return -ENOMEM;
> > +		}
> >
> > -	if (!fusion->cmd_list) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of
> memory. Could not alloc "
> > -		       "memory for cmd_list_fusion\n");
> > -		goto fail_cmd_list;
> > +		fusion->rdpq_virt[i].RDPQBaseAddress =
> > +			fusion->reply_frames_desc_phys[i];
> > +
> > +		reply_desc = fusion->reply_frames_desc[i];
> > +		for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
> > +			reply_desc->Words = ULLONG_MAX;
> >  	}
> > +	return 0;
> > +}
> >
> > -	max_cmd = instance->max_fw_cmds;
> > -	for (i = 0; i < max_cmd; i++) {
> > -		fusion->cmd_list[i] = kmalloc(sizeof(struct
> megasas_cmd_fusion),
> > -					      GFP_KERNEL);
> > -		if (!fusion->cmd_list[i]) {
> > -			dev_err(&instance->pdev->dev, "Could not alloc cmd
> list fusion\n");
> > +static void
> > +megasas_free_rdpq_fusion(struct megasas_instance *instance) {
> >
> > -			for (j = 0; j < i; j++)
> > -				kfree(fusion->cmd_list[j]);
> > +	int i;
> > +	struct fusion_context *fusion;
> >
> > -			kfree(fusion->cmd_list);
> > -			fusion->cmd_list = NULL;
> > -			goto fail_cmd_list;
> > -		}
> > +	fusion = instance->ctrl_context;
> > +
> > +	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
> > +		if (fusion->reply_frames_desc[i])
> > +			pci_pool_free(fusion->reply_frames_desc_pool,
> > +				fusion->reply_frames_desc[i],
> > +				fusion->reply_frames_desc_phys[i]);
> >  	}
> >
> > -	/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list
*/
> > -	io_req_base = fusion->io_request_frames +
> > -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> > -	io_req_base_phys = fusion->io_request_frames_phys +
> > -		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> > +	if (fusion->reply_frames_desc_pool)
> > +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > +
> > +	if (fusion->rdpq_virt)
> > +		pci_free_consistent(instance->pdev,
> > +			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) *
> MAX_MSIX_QUEUES_FUSION,
> > +			fusion->rdpq_virt, fusion->rdpq_phys); }
> > +
> > +static void
> > +megasas_free_reply_fusion(struct megasas_instance *instance) {
> > +
> > +	struct fusion_context *fusion;
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	if (fusion->reply_frames_desc[0])
> > +		pci_pool_free(fusion->reply_frames_desc_pool,
> > +			fusion->reply_frames_desc[0],
> > +			fusion->reply_frames_desc_phys[0]);
> > +
> > +	if (fusion->reply_frames_desc_pool)
> > +		pci_pool_destroy(fusion->reply_frames_desc_pool);
> > +
> > +}
> > +
> > +
> > +/**
> > + * megasas_alloc_cmds_fusion -	Allocates the command packets
> > + * @instance:		Adapter soft state
> > + *
> > + *
> > + * Each frame has a 32-bit field called context. This context is used
> > +to get
> > + * back the megasas_cmd_fusion from the frame when a frame gets
> > +completed
> > + * In this driver, the 32 bit values are the indices into an array
cmd_list.
> > + * This array is used only to look up the megasas_cmd_fusion given
the
> context.
> > + * The free commands themselves are maintained in a linked list
called
> cmd_pool.
> > + *
> > + * cmds are formed in the io_request and sg_frame members of the
> > + * megasas_cmd_fusion. The context field is used to get a request
> > +descriptor
> > + * and is used as SMID of the cmd.
> > + * SMID value range is from 1 to max_fw_cmds.
> > + */
> > +int
> > +megasas_alloc_cmds_fusion(struct megasas_instance *instance) {
> > +	int i;
> > +	struct fusion_context *fusion;
> > +	struct megasas_cmd_fusion *cmd;
> > +	u32 offset;
> > +	dma_addr_t io_req_base_phys;
> > +	u8 *io_req_base;
> > +
> > +
> > +	fusion = instance->ctrl_context;
> > +
> > +	if (megasas_alloc_cmdlist_fusion(instance))
>
> We may need to call megasas_free_cmds_fusion here too (to free fusion-
> >cmd_list)
I will work on all error condition handling stuff..
>
> > +		return -ENOMEM;
> > +
> > +	if (megasas_alloc_request_fusion(instance))
> > +		goto fail_exit;
> > +
> > +	if (instance->is_rdpq) {
> > +		if (megasas_alloc_rdpq_fusion(instance))
> > +			goto fail_exit;
> > +	} else
> > +		if (megasas_alloc_reply_fusion(instance))
> > +			goto fail_exit;
> > +
> > +
> > +	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd
list */
> > +	io_req_base = fusion->io_request_frames +
> MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> > +	io_req_base_phys = fusion->io_request_frames_phys +
> > +MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
> >
> >  	/*
> >  	 * Add all the commands to command pool (fusion->cmd_pool)
> >  	 */
> >
> >  	/* SMID 0 is reserved. Set SMID/index from 1 */
> > -	for (i = 0; i < max_cmd; i++) {
> > +	for (i = 0; i < instance->max_fw_cmds; i++) {
> >  		cmd = fusion->cmd_list[i];
> >  		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
> >  		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
>
> That memset was already done in megasas_alloc_cmdlist_fusion
Will use kzalloc instead of kmalloc to avoid all memset to zero
instructions.
>
> > @@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct
> megasas_instance *instance)
> >  		cmd->io_request_phys_addr = io_req_base_phys + offset;
> >  	}/
> >
> > -	/*
> > -	 * Create a frame pool and assign one frame to each cmd
> > -	 */
> > -	if (megasas_create_frame_pool_fusion(instance)) {
> > -		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error
> creating frame DMA pool\n");
> > -		megasas_free_cmds_fusion(instance);
> > -		goto fail_req_desc;
> > -	}
> > +	if (megasas_create_sg_sense_fusion(instance))
> > +		goto fail_exit;
> >
> >  	return 0;
> >
> > -fail_cmd_list:
> > -	pci_pool_free(fusion->io_request_frames_pool, fusion-
> >io_request_frames,
> > -		      fusion->io_request_frames_phys);
> > -	pci_pool_destroy(fusion->io_request_frames_pool);
> > -fail_io_frames:
> > -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> > -			  fusion->reply_frames_desc,
> > -			  fusion->reply_frames_desc_phys);
> > -	pci_pool_free(fusion->reply_frames_desc_pool,
> > -		      fusion->reply_frames_desc,
> > -		      fusion->reply_frames_desc_phys);
> > -	pci_pool_destroy(fusion->reply_frames_desc_pool);
> > -
> > -fail_reply_desc:
> > -	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
> > -			  fusion->req_frames_desc,
> > -			  fusion->req_frames_desc_phys);
> > -fail_req_desc:
> > +fail_exit:
> > +	megasas_free_cmds_fusion(instance);
> >  	return -ENOMEM;
> >  }
> >
> > @@ -594,16 +646,17 @@ int
> >  megasas_ioc_init_fusion(struct megasas_instance *instance)  {
> >  	struct megasas_init_frame *init_frame;
> > -	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
> > +	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
> >  	dma_addr_t	ioc_init_handle;
> >  	struct megasas_cmd *cmd;
> > -	u8 ret;
> > +	u8 ret, cur_rdpq_mode;
> >  	struct fusion_context *fusion;
> >  	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
> >  	int i;
> >  	struct megasas_header *frame_hdr;
> >  	const char *sys_info;
> >  	MFI_CAPABILITIES *drv_ops;
> > +	u32 scratch_pad_2;
> >
> >  	fusion = instance->ctrl_context;
> >
> > @@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance
> *instance)
> >  		goto fail_get_cmd;
> >  	}
> >
> > +	scratch_pad_2 = readl
> > +		(&instance->reg_set->outbound_scratch_pad_2);
> > +
> > +	cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
> > +
> > +	if (instance->is_rdpq && !cur_rdpq_mode) {
> > +		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT
> SUPPORTED*"
> > +			" from RDPQ mode to non RDPQ mode\n");
>
> How does this work ? is_rdpq is set in megasas_init_fw only when the fw
> supports it, why do you test it here again ? I think I'm miss something.

"is_rdpq" stores the capability of firmware flashed during driver load and
"cur_rdpq_mode" tells capability of upgraded/downgraded firmware(OFU)
without reloading driver.
This condition is just to ensure that firmware downgrade from RDPQ mode to
non RDPQ mode should not be allowed.
>
> Tomas
>
> > +		ret = 1;
> > +		goto fail_fw_init;
> > +	}
> > +
> >  	IOCInitMessage =
> >  	  dma_alloc_coherent(&instance->pdev->dev,
> >  			     sizeof(struct MPI2_IOC_INIT_REQUEST), @@
-636,7
> +701,11 @@
> > megasas_ioc_init_fusion(struct megasas_instance *instance)
> >  	IOCInitMessage->SystemRequestFrameSize =
> > cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
> >
> >  	IOCInitMessage->ReplyDescriptorPostQueueDepth =
> cpu_to_le16(fusion->reply_q_depth);
> > -	IOCInitMessage->ReplyDescriptorPostQueueAddress	=
> cpu_to_le64(fusion->reply_frames_desc_phys);
> > +	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance-
> >is_rdpq ?
> > +			cpu_to_le64(fusion->rdpq_phys) :
> > +			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
> > +	IOCInitMessage->MsgFlags = instance->is_rdpq ?
> > +			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
> >  	IOCInitMessage->SystemRequestFrameBaseAddress =
> cpu_to_le64(fusion->io_request_frames_phys);
> >  	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
> >  	init_frame = (struct megasas_init_frame *)cmd->frame; @@ -1087,7
> > +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance
> *instance)
> >  	 */
> >  	instance->max_fw_cmds =
> >  		instance->instancet->read_fw_status_reg(reg_set) &
0x00FFFF;
> > -	instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
> > +	dev_info(&instance->pdev->dev,
> > +		"firmware support max fw cmd\t: (%d)\n", instance-
> >max_fw_cmds);
> > +	if (!instance->is_rdpq)
> > +		instance->max_fw_cmds = min_t(u16, instance-
> >max_fw_cmds, 1024);
> >
> >  	/*
> >  	 * Reduce the max supported cmds by 1. This is to ensure that the
@@
> > -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance
> *instance, u32 MSIxIndex)
> >  	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
> >  		return IRQ_HANDLED;
> >
> > -	desc = fusion->reply_frames_desc;
> > -	desc += ((MSIxIndex * fusion->reply_alloc_sz)/
> > -		 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
> > -		fusion->last_reply_idx[MSIxIndex];
> > +	desc = fusion->reply_frames_desc[MSIxIndex] +
> > +				fusion->last_reply_idx[MSIxIndex];
> >
> >  	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
> *)desc;
> >
> > @@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance
> > *instance, u32 MSIxIndex)
> >
> >  		/* Get the next reply descriptor */
> >  		if (!fusion->last_reply_idx[MSIxIndex])
> > -			desc = fusion->reply_frames_desc +
> > -				((MSIxIndex * fusion->reply_alloc_sz)/
> > -				 sizeof(union
> MPI2_REPLY_DESCRIPTORS_UNION));
> > +			desc = fusion->reply_frames_desc[MSIxIndex];
> >  		else
> >  			desc++;
> >
> > @@ -2688,17 +2756,18 @@ out:
> >
> >  void  megasas_reset_reply_desc(struct megasas_instance *instance)  {
> > -	int i, count;
> > +	int i, j, count;
> >  	struct fusion_context *fusion;
> >  	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
> >
> >  	fusion = instance->ctrl_context;
> >  	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
> > -	for (i = 0 ; i < count ; i++)
> > +	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 * count; i++, reply_desc++)
> > -		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> > +		reply_desc = fusion->reply_frames_desc[i];
> > +		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
> > +			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
> > +	}
> >  }
> >
> >  /*
> > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > index db0978d..80eaee2 100644
> > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
> > @@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
> >  	struct MR_PD_CFG_SEQ seq[1];
> >  } __packed;
> >
> > +struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
> > +	u64 RDPQBaseAddress;
> > +	u32 Reserved1;
> > +	u32 Reserved2;
> > +};
> > +
> >  struct fusion_context {
> >  	struct megasas_cmd_fusion **cmd_list;
> >  	dma_addr_t req_frames_desc_phys;
> > @@ -940,8 +946,8 @@ struct fusion_context {
> >  	struct dma_pool *sg_dma_pool;
> >  	struct dma_pool *sense_dma_pool;
> >
> > -	dma_addr_t reply_frames_desc_phys;
> > -	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
> > +	dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
> > +	union MPI2_REPLY_DESCRIPTORS_UNION
> > +*reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
> >  	struct dma_pool *reply_frames_desc_pool;
> >
> >  	u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
> > @@ -951,6 +957,8 @@ struct fusion_context {
> >  	u32 reply_alloc_sz;
> >  	u32 io_frames_alloc_sz;
> >
> > +	struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
> > +	dma_addr_t rdpq_phys;
> >  	u16	max_sge_in_main_msg;
> >  	u16	max_sge_in_chain;
> >
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 01135be..c539516 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -152,6 +152,7 @@ 
 #define MFI_RESET_FLAGS				MFI_INIT_READY| \
 						MFI_INIT_MFIMODE| \
 						MFI_INIT_ABORT
+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE    (0x01)
 
 /*
  * MFI frame flags
@@ -1416,6 +1417,7 @@  enum DCMD_TIMEOUT_ACTION {
 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET          0X003FC000
 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
 #define MR_MAX_MSIX_REG_ARRAY                   16
+#define MR_RDPQ_MODE_OFFSET			0X00800000
 /*
 * register set for both 1068 and 1078 controllers
 * structure extended for 1078 registers
@@ -1455,8 +1457,9 @@  struct megasas_register_set {
 
 	u32 	outbound_scratch_pad ;		/*00B0h*/
 	u32	outbound_scratch_pad_2;         /*00B4h*/
+	u32	outbound_scratch_pad_3;         /*00B8h*/
 
-	u32	reserved_4[2];			/*00B8h*/
+	u32	reserved_4;			/*00BCh*/
 
 	u32 	inbound_low_queue_port ;	/*00C0h*/
 
@@ -2117,6 +2120,7 @@  struct megasas_instance {
 	u8 mask_interrupts;
 	u16 max_chain_frame_sz;
 	u8 is_imr;
+	u8 is_rdpq;
 	bool dev_handle;
 };
 struct MR_LD_VF_MAP {
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index df93fa1..a3b63fa 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -92,6 +92,10 @@  int smp_affinity_enable = 1;
 module_param(smp_affinity_enable, int, S_IRUGO);
 MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
 
+int rdpq_enable = 1;
+module_param(rdpq_enable, int, S_IRUGO);
+MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
@@ -5081,6 +5085,9 @@  static int megasas_init_fw(struct megasas_instance *instance)
 				instance->msix_vectors = ((scratch_pad_2
 					& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
 					>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
+				if (rdpq_enable)
+					instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
+								1 : 0;
 				fw_msix_count = instance->msix_vectors;
 				/* Save 1-15 reply post index address to local memory
 				 * Index 0 is already saved from reg offset
@@ -5117,6 +5124,8 @@  static int megasas_init_fw(struct megasas_instance *instance)
 	dev_info(&instance->pdev->dev,
 		"current msix/online cpus\t: (%d/%d)\n",
 		instance->msix_vectors, (unsigned int)num_online_cpus());
+	dev_info(&instance->pdev->dev,
+		"firmware supports rdpq mode\t: (%d)\n", instance->is_rdpq);
 
 	tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
 		(unsigned long)instance);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index e8730ef..aca0cd3 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -92,6 +92,8 @@  void megasas_start_timer(struct megasas_instance *instance,
 			 void *fn, unsigned long interval);
 extern struct megasas_mgmt_info megasas_mgmt_info;
 extern int resetwaittime;
+static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
+static void megasas_free_reply_fusion(struct megasas_instance *instance);
 
 
 
@@ -205,112 +207,71 @@  megasas_fire_cmd_fusion(struct megasas_instance *instance,
 #endif
 }
 
-
 /**
- * megasas_teardown_frame_pool_fusion -	Destroy the cmd frame DMA pool
- * @instance:				Adapter soft state
+ * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
+ * @instance:		Adapter soft state
  */
-static void megasas_teardown_frame_pool_fusion(
-	struct megasas_instance *instance)
+void
+megasas_free_cmds_fusion(struct megasas_instance *instance)
 {
 	int i;
 	struct fusion_context *fusion = instance->ctrl_context;
-
-	u16 max_cmd = instance->max_fw_cmds;
-
 	struct megasas_cmd_fusion *cmd;
 
-	if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) {
-		dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, "
-		       "sense pool : %p\n", fusion->sg_dma_pool,
-		       fusion->sense_dma_pool);
-		return;
-	}
-
-	/*
-	 * Return all frames to pool
-	 */
-	for (i = 0; i < max_cmd; i++) {
-
+	/* SG, Sense */
+	for (i = 0; i < instance->max_fw_cmds; i++) {
 		cmd = fusion->cmd_list[i];
-
 		if (cmd->sg_frame)
 			pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
-				      cmd->sg_frame_phys_addr);
-
+			      cmd->sg_frame_phys_addr);
 		if (cmd->sense)
 			pci_pool_free(fusion->sense_dma_pool, cmd->sense,
-				      cmd->sense_phys_addr);
+			      cmd->sense_phys_addr);
 	}
 
-	/*
-	 * Now destroy the pool itself
-	 */
-	pci_pool_destroy(fusion->sg_dma_pool);
-	pci_pool_destroy(fusion->sense_dma_pool);
-
-	fusion->sg_dma_pool = NULL;
-	fusion->sense_dma_pool = NULL;
-}
-
-/**
- * megasas_free_cmds_fusion -	Free all the cmds in the free cmd pool
- * @instance:		Adapter soft state
- */
-void
-megasas_free_cmds_fusion(struct megasas_instance *instance)
-{
-	int i;
-	struct fusion_context *fusion = instance->ctrl_context;
-
-	u32 max_cmds, req_sz, reply_sz, io_frames_sz;
-
+	if (fusion->sg_dma_pool) {
+		pci_pool_destroy(fusion->sg_dma_pool);
+		fusion->sg_dma_pool = NULL;
+	}
+	if (fusion->sense_dma_pool) {
+		pci_pool_destroy(fusion->sense_dma_pool);
+		fusion->sense_dma_pool = NULL;
+	}
 
-	req_sz = fusion->request_alloc_sz;
-	reply_sz = fusion->reply_alloc_sz;
-	io_frames_sz = fusion->io_frames_alloc_sz;
 
-	max_cmds = instance->max_fw_cmds;
+	/* Reply Frame, Desc*/
+	if (instance->is_rdpq)
+		megasas_free_rdpq_fusion(instance);
+	else
+		megasas_free_reply_fusion(instance);
 
-	/* Free descriptors and request Frames memory */
+	/* Request Frame, Desc*/
 	if (fusion->req_frames_desc)
-		dma_free_coherent(&instance->pdev->dev, req_sz,
-				  fusion->req_frames_desc,
-				  fusion->req_frames_desc_phys);
-
-	if (fusion->reply_frames_desc) {
-		pci_pool_free(fusion->reply_frames_desc_pool,
-			      fusion->reply_frames_desc,
-			      fusion->reply_frames_desc_phys);
-		pci_pool_destroy(fusion->reply_frames_desc_pool);
-	}
-
-	if (fusion->io_request_frames) {
+		dma_free_coherent(&instance->pdev->dev,
+			fusion->request_alloc_sz, fusion->req_frames_desc,
+			fusion->req_frames_desc_phys);
+	if (fusion->io_request_frames)
 		pci_pool_free(fusion->io_request_frames_pool,
-			      fusion->io_request_frames,
-			      fusion->io_request_frames_phys);
+			fusion->io_request_frames,
+			fusion->io_request_frames_phys);
+	if (fusion->io_request_frames_pool)
 		pci_pool_destroy(fusion->io_request_frames_pool);
-	}
 
-	/* Free the Fusion frame pool */
-	megasas_teardown_frame_pool_fusion(instance);
 
-	/* Free all the commands in the cmd_list */
-	for (i = 0; i < max_cmds; i++)
+	/* cmd_list */
+	for (i = 0; i < instance->max_fw_cmds; i++)
 		kfree(fusion->cmd_list[i]);
 
-	/* Free the cmd_list buffer itself */
 	kfree(fusion->cmd_list);
 	fusion->cmd_list = NULL;
-
 }
 
 /**
- * megasas_create_frame_pool_fusion -	Creates DMA pool for cmd frames
+ * megasas_create_sg_sense_fusion -	Creates DMA pool for cmd frames
  * @instance:			Adapter soft state
  *
  */
-static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
+static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
 {
 	int i;
 	u32 max_cmd;
@@ -321,186 +282,299 @@  static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
 	max_cmd = instance->max_fw_cmds;
 
 
-	/*
-	 * Use DMA pool facility provided by PCI layer
-	 */
-
-	fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev,
-						instance->max_chain_frame_sz,
-						4, 0);
-	if (!fusion->sg_dma_pool) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
-		return -ENOMEM;
-	}
-	fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
-						 instance->pdev,
-						 SCSI_SENSE_BUFFERSIZE, 64, 0);
+	fusion->sg_dma_pool =
+			pci_pool_create("mr_sg", instance->pdev,
+				instance->max_chain_frame_sz, 4, 0);
+	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
+	fusion->sense_dma_pool =
+			pci_pool_create("mr_sense", instance->pdev,
+				SCSI_SENSE_BUFFERSIZE, 64, 0);
 
-	if (!fusion->sense_dma_pool) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n");
-		pci_pool_destroy(fusion->sg_dma_pool);
-		fusion->sg_dma_pool = NULL;
-		return -ENOMEM;
-	}
+	if (!fusion->sense_dma_pool || !fusion->sg_dma_pool)
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
 
 	/*
 	 * Allocate and attach a frame to each of the commands in cmd_list
 	 */
 	for (i = 0; i < max_cmd; i++) {
-
 		cmd = fusion->cmd_list[i];
-
 		cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
-					       GFP_KERNEL,
-					       &cmd->sg_frame_phys_addr);
+					GFP_KERNEL, &cmd->sg_frame_phys_addr);
 
 		cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
-					    GFP_KERNEL, &cmd->sense_phys_addr);
-		/*
-		 * megasas_teardown_frame_pool_fusion() takes care of freeing
-		 * whatever has been allocated
-		 */
+					GFP_KERNEL, &cmd->sense_phys_addr);
 		if (!cmd->sg_frame || !cmd->sense) {
-			dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n");
-			megasas_teardown_frame_pool_fusion(instance);
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
 			return -ENOMEM;
 		}
 	}
 	return 0;
 }
 
-/**
- * megasas_alloc_cmds_fusion -	Allocates the command packets
- * @instance:		Adapter soft state
- *
- *
- * Each frame has a 32-bit field called context. This context is used to get
- * back the megasas_cmd_fusion from the frame when a frame gets completed
- * In this driver, the 32 bit values are the indices into an array cmd_list.
- * This array is used only to look up the megasas_cmd_fusion given the context.
- * The free commands themselves are maintained in a linked list called cmd_pool.
- *
- * cmds are formed in the io_request and sg_frame members of the
- * megasas_cmd_fusion. The context field is used to get a request descriptor
- * and is used as SMID of the cmd.
- * SMID value range is from 1 to max_fw_cmds.
- */
 int
-megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
 {
-	int i, j, count;
-	u32 max_cmd, io_frames_sz;
+	u32 max_cmd, i;
 	struct fusion_context *fusion;
-	struct megasas_cmd_fusion *cmd;
-	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
-	u32 offset;
-	dma_addr_t io_req_base_phys;
-	u8 *io_req_base;
 
 	fusion = instance->ctrl_context;
 
 	max_cmd = instance->max_fw_cmds;
 
+	/*
+	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
+	 * Allocate the dynamic array first and then allocate individual
+	 * commands.
+	 */
+	fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
+						GFP_KERNEL);
+	if (!fusion->cmd_list) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+	memset(fusion->cmd_list, 0,
+		sizeof(struct megasas_cmd_fusion *) * max_cmd);
+
+	for (i = 0; i < max_cmd; i++) {
+		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
+					      GFP_KERNEL);
+		if (!fusion->cmd_list[i]) {
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
+			return -ENOMEM;
+		}
+		memset(fusion->cmd_list[i], 0, sizeof(struct megasas_cmd_fusion));
+	}
+	return 0;
+}
+int
+megasas_alloc_request_fusion(struct megasas_instance *instance)
+{
+	struct fusion_context *fusion;
+
+	fusion = instance->ctrl_context;
+
 	fusion->req_frames_desc =
 		dma_alloc_coherent(&instance->pdev->dev,
-				   fusion->request_alloc_sz,
-				   &fusion->req_frames_desc_phys, GFP_KERNEL);
-
+			fusion->request_alloc_sz,
+			&fusion->req_frames_desc_phys, GFP_KERNEL);
 	if (!fusion->req_frames_desc) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "request_frames\n");
-		goto fail_req_desc;
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	fusion->io_request_frames_pool =
+			pci_pool_create("mr_ioreq", instance->pdev,
+				fusion->io_frames_alloc_sz, 16, 0);
+
+	if (!fusion->io_request_frames_pool) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	fusion->io_request_frames =
+			pci_pool_alloc(fusion->io_request_frames_pool,
+				GFP_KERNEL, &fusion->io_request_frames_phys);
+	if (!fusion->io_request_frames) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
+	return 0;
+}
+
+int
+megasas_alloc_reply_fusion(struct megasas_instance *instance)
+{
+	int i, count;
+	struct fusion_context *fusion;
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+	fusion = instance->ctrl_context;
 
 	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
 	fusion->reply_frames_desc_pool =
-		pci_pool_create("reply_frames pool", instance->pdev,
+			pci_pool_create("mr_reply", instance->pdev,
 				fusion->reply_alloc_sz * count, 16, 0);
 
 	if (!fusion->reply_frames_desc_pool) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "reply_frame pool\n");
-		goto fail_reply_desc;
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	fusion->reply_frames_desc =
-		pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL,
-			       &fusion->reply_frames_desc_phys);
-	if (!fusion->reply_frames_desc) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "reply_frame pool\n");
-		pci_pool_destroy(fusion->reply_frames_desc_pool);
-		goto fail_reply_desc;
+	fusion->reply_frames_desc[0] =
+		pci_pool_alloc(fusion->reply_frames_desc_pool,
+			GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
+	if (!fusion->reply_frames_desc[0]) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
-
-	reply_desc = fusion->reply_frames_desc;
+	reply_desc = fusion->reply_frames_desc[0];
 	for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
-		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+		reply_desc->Words = ULLONG_MAX;
 
-	io_frames_sz = fusion->io_frames_alloc_sz;
+	/* This is not a rdpq mode, but driver still populate
+	 * reply_frame_desc array to use same msix index in ISR path.
+	 */
+	for (i = 0; i < (count - 1); i++)
+		fusion->reply_frames_desc[i + 1] =
+			fusion->reply_frames_desc[i] +
+			(fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
 
-	fusion->io_request_frames_pool =
-		pci_pool_create("io_request_frames pool", instance->pdev,
-				fusion->io_frames_alloc_sz, 16, 0);
+	return 0;
+}
 
-	if (!fusion->io_request_frames_pool) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "io_request_frame pool\n");
-		goto fail_io_frames;
+int
+megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
+{
+	int i, j, count;
+	struct fusion_context *fusion;
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
+
+	fusion = instance->ctrl_context;
+
+	fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
+				sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+				&fusion->rdpq_phys);
+	if (!fusion->rdpq_virt) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	fusion->io_request_frames =
-		pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL,
-			       &fusion->io_request_frames_phys);
-	if (!fusion->io_request_frames) {
-		dev_err(&instance->pdev->dev, "Could not allocate memory for "
-		       "io_request_frames frames\n");
-		pci_pool_destroy(fusion->io_request_frames_pool);
-		goto fail_io_frames;
+	memset(fusion->rdpq_virt, 0,
+			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
+	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+	fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
+							 instance->pdev, fusion->reply_alloc_sz, 16, 0);
+
+	if (!fusion->reply_frames_desc_pool) {
+		dev_err(&instance->pdev->dev,
+			"Failed from %s %d\n",  __func__, __LINE__);
+		return -ENOMEM;
 	}
 
-	/*
-	 * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
-	 * Allocate the dynamic array first and then allocate individual
-	 * commands.
-	 */
-	fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *)
-				   * max_cmd, GFP_KERNEL);
+	for (i = 0; i < count; i++) {
+		fusion->reply_frames_desc[i] =
+				pci_pool_alloc(fusion->reply_frames_desc_pool,
+					GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
+		if (!fusion->reply_frames_desc[i]) {
+			dev_err(&instance->pdev->dev,
+				"Failed from %s %d\n",  __func__, __LINE__);
+			return -ENOMEM;
+		}
 
-	if (!fusion->cmd_list) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc "
-		       "memory for cmd_list_fusion\n");
-		goto fail_cmd_list;
+		fusion->rdpq_virt[i].RDPQBaseAddress =
+			fusion->reply_frames_desc_phys[i];
+
+		reply_desc = fusion->reply_frames_desc[i];
+		for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
+			reply_desc->Words = ULLONG_MAX;
 	}
+	return 0;
+}
 
-	max_cmd = instance->max_fw_cmds;
-	for (i = 0; i < max_cmd; i++) {
-		fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
-					      GFP_KERNEL);
-		if (!fusion->cmd_list[i]) {
-			dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
+static void
+megasas_free_rdpq_fusion(struct megasas_instance *instance) {
 
-			for (j = 0; j < i; j++)
-				kfree(fusion->cmd_list[j]);
+	int i;
+	struct fusion_context *fusion;
 
-			kfree(fusion->cmd_list);
-			fusion->cmd_list = NULL;
-			goto fail_cmd_list;
-		}
+	fusion = instance->ctrl_context;
+
+	for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
+		if (fusion->reply_frames_desc[i])
+			pci_pool_free(fusion->reply_frames_desc_pool,
+				fusion->reply_frames_desc[i],
+				fusion->reply_frames_desc_phys[i]);
 	}
 
-	/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */
-	io_req_base = fusion->io_request_frames +
-		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
-	io_req_base_phys = fusion->io_request_frames_phys +
-		MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+	if (fusion->reply_frames_desc_pool)
+		pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+	if (fusion->rdpq_virt)
+		pci_free_consistent(instance->pdev,
+			sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
+			fusion->rdpq_virt, fusion->rdpq_phys);
+}
+
+static void
+megasas_free_reply_fusion(struct megasas_instance *instance) {
+
+	struct fusion_context *fusion;
+
+	fusion = instance->ctrl_context;
+
+	if (fusion->reply_frames_desc[0])
+		pci_pool_free(fusion->reply_frames_desc_pool,
+			fusion->reply_frames_desc[0],
+			fusion->reply_frames_desc_phys[0]);
+
+	if (fusion->reply_frames_desc_pool)
+		pci_pool_destroy(fusion->reply_frames_desc_pool);
+
+}
+
+
+/**
+ * megasas_alloc_cmds_fusion -	Allocates the command packets
+ * @instance:		Adapter soft state
+ *
+ *
+ * Each frame has a 32-bit field called context. This context is used to get
+ * back the megasas_cmd_fusion from the frame when a frame gets completed
+ * In this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd_fusion given the context.
+ * The free commands themselves are maintained in a linked list called cmd_pool.
+ *
+ * cmds are formed in the io_request and sg_frame members of the
+ * megasas_cmd_fusion. The context field is used to get a request descriptor
+ * and is used as SMID of the cmd.
+ * SMID value range is from 1 to max_fw_cmds.
+ */
+int
+megasas_alloc_cmds_fusion(struct megasas_instance *instance)
+{
+	int i;
+	struct fusion_context *fusion;
+	struct megasas_cmd_fusion *cmd;
+	u32 offset;
+	dma_addr_t io_req_base_phys;
+	u8 *io_req_base;
+
+
+	fusion = instance->ctrl_context;
+
+	if (megasas_alloc_cmdlist_fusion(instance))
+		return -ENOMEM;
+
+	if (megasas_alloc_request_fusion(instance))
+		goto fail_exit;
+
+	if (instance->is_rdpq) {
+		if (megasas_alloc_rdpq_fusion(instance))
+			goto fail_exit;
+	} else
+		if (megasas_alloc_reply_fusion(instance))
+			goto fail_exit;
+
+
+	/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
+	io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
+	io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
 
 	/*
 	 * Add all the commands to command pool (fusion->cmd_pool)
 	 */
 
 	/* SMID 0 is reserved. Set SMID/index from 1 */
-	for (i = 0; i < max_cmd; i++) {
+	for (i = 0; i < instance->max_fw_cmds; i++) {
 		cmd = fusion->cmd_list[i];
 		offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
 		memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
@@ -518,35 +592,13 @@  megasas_alloc_cmds_fusion(struct megasas_instance *instance)
 		cmd->io_request_phys_addr = io_req_base_phys + offset;
 	}
 
-	/*
-	 * Create a frame pool and assign one frame to each cmd
-	 */
-	if (megasas_create_frame_pool_fusion(instance)) {
-		dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
-		megasas_free_cmds_fusion(instance);
-		goto fail_req_desc;
-	}
+	if (megasas_create_sg_sense_fusion(instance))
+		goto fail_exit;
 
 	return 0;
 
-fail_cmd_list:
-	pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames,
-		      fusion->io_request_frames_phys);
-	pci_pool_destroy(fusion->io_request_frames_pool);
-fail_io_frames:
-	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
-			  fusion->reply_frames_desc,
-			  fusion->reply_frames_desc_phys);
-	pci_pool_free(fusion->reply_frames_desc_pool,
-		      fusion->reply_frames_desc,
-		      fusion->reply_frames_desc_phys);
-	pci_pool_destroy(fusion->reply_frames_desc_pool);
-
-fail_reply_desc:
-	dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
-			  fusion->req_frames_desc,
-			  fusion->req_frames_desc_phys);
-fail_req_desc:
+fail_exit:
+	megasas_free_cmds_fusion(instance);
 	return -ENOMEM;
 }
 
@@ -594,16 +646,17 @@  int
 megasas_ioc_init_fusion(struct megasas_instance *instance)
 {
 	struct megasas_init_frame *init_frame;
-	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage;
+	struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
 	dma_addr_t	ioc_init_handle;
 	struct megasas_cmd *cmd;
-	u8 ret;
+	u8 ret, cur_rdpq_mode;
 	struct fusion_context *fusion;
 	union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
 	int i;
 	struct megasas_header *frame_hdr;
 	const char *sys_info;
 	MFI_CAPABILITIES *drv_ops;
+	u32 scratch_pad_2;
 
 	fusion = instance->ctrl_context;
 
@@ -615,6 +668,18 @@  megasas_ioc_init_fusion(struct megasas_instance *instance)
 		goto fail_get_cmd;
 	}
 
+	scratch_pad_2 = readl
+		(&instance->reg_set->outbound_scratch_pad_2);
+
+	cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
+
+	if (instance->is_rdpq && !cur_rdpq_mode) {
+		dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
+			" from RDPQ mode to non RDPQ mode\n");
+		ret = 1;
+		goto fail_fw_init;
+	}
+
 	IOCInitMessage =
 	  dma_alloc_coherent(&instance->pdev->dev,
 			     sizeof(struct MPI2_IOC_INIT_REQUEST),
@@ -636,7 +701,11 @@  megasas_ioc_init_fusion(struct megasas_instance *instance)
 	IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
 
 	IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
-	IOCInitMessage->ReplyDescriptorPostQueueAddress	= cpu_to_le64(fusion->reply_frames_desc_phys);
+	IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
+			cpu_to_le64(fusion->rdpq_phys) :
+			cpu_to_le64(fusion->reply_frames_desc_phys[0]);
+	IOCInitMessage->MsgFlags = instance->is_rdpq ?
+			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
 	IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
 	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
 	init_frame = (struct megasas_init_frame *)cmd->frame;
@@ -1087,7 +1156,10 @@  megasas_init_adapter_fusion(struct megasas_instance *instance)
 	 */
 	instance->max_fw_cmds =
 		instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
-	instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008);
+	dev_info(&instance->pdev->dev,
+		"firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds);
+	if (!instance->is_rdpq)
+		instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
 
 	/*
 	 * Reduce the max supported cmds by 1. This is to ensure that the
@@ -2110,10 +2182,8 @@  complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
 		return IRQ_HANDLED;
 
-	desc = fusion->reply_frames_desc;
-	desc += ((MSIxIndex * fusion->reply_alloc_sz)/
-		 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
-		fusion->last_reply_idx[MSIxIndex];
+	desc = fusion->reply_frames_desc[MSIxIndex] +
+				fusion->last_reply_idx[MSIxIndex];
 
 	reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
 
@@ -2208,9 +2278,7 @@  complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 
 		/* Get the next reply descriptor */
 		if (!fusion->last_reply_idx[MSIxIndex])
-			desc = fusion->reply_frames_desc +
-				((MSIxIndex * fusion->reply_alloc_sz)/
-				 sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
+			desc = fusion->reply_frames_desc[MSIxIndex];
 		else
 			desc++;
 
@@ -2688,17 +2756,18 @@  out:
 
 void  megasas_reset_reply_desc(struct megasas_instance *instance)
 {
-	int i, count;
+	int i, j, count;
 	struct fusion_context *fusion;
 	union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
 
 	fusion = instance->ctrl_context;
 	count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
-	for (i = 0 ; i < count ; i++)
+	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 * count; i++, reply_desc++)
-		reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+		reply_desc = fusion->reply_frames_desc[i];
+		for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
+			reply_desc->Words = cpu_to_le64(ULLONG_MAX);
+	}
 }
 
 /*
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index db0978d..80eaee2 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -928,6 +928,12 @@  struct MR_PD_CFG_SEQ_NUM_SYNC {
 	struct MR_PD_CFG_SEQ seq[1];
 } __packed;
 
+struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
+	u64 RDPQBaseAddress;
+	u32 Reserved1;
+	u32 Reserved2;
+};
+
 struct fusion_context {
 	struct megasas_cmd_fusion **cmd_list;
 	dma_addr_t req_frames_desc_phys;
@@ -940,8 +946,8 @@  struct fusion_context {
 	struct dma_pool *sg_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
-	dma_addr_t reply_frames_desc_phys;
-	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc;
+	dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
+	union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
 	struct dma_pool *reply_frames_desc_pool;
 
 	u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
@@ -951,6 +957,8 @@  struct fusion_context {
 	u32 reply_alloc_sz;
 	u32 io_frames_alloc_sz;
 
+	struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
+	dma_addr_t rdpq_phys;
 	u16	max_sge_in_main_msg;
 	u16	max_sge_in_chain;