linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RESEND][PATCH 7/8][SCSI]mpt3sas: Added Reply Descriptor Post Queue (RDPQ) Array support
@ 2014-06-25 10:41 Reddy, Sreekanth
  2014-08-05 15:24 ` Tomas Henzl
  0 siblings, 1 reply; 4+ messages in thread
From: Reddy, Sreekanth @ 2014-06-25 10:41 UTC (permalink / raw)
  To: jejb, JBottomley
  Cc: linux-scsi, Sathya.Prakash, Nagalakshmi.Nandigama,
	sreekanth.reddy, linux-kernel, hch, martin.petersen

Up to now, Driver allocates a single contiguous block of memory
pool for all reply queues and passes down a single address in the
ReplyDescriptorPostQueueAddress field of the IOC Init Request
Message to the firmware.

When firmware receives this address, it will program each of the
Reply Descriptor Post Queue registers, as each reply queue has its
own register. Thus the firmware, starting from a base address it
determines the starting address of the subsequent reply queues
through some simple arithmetic calculations.

The size of this contiguous block of memory pool is directly proportional
to number of MSI-X vectors and the HBA queue depth. For example higher
MSIX vectors requires larger contiguous block of memory pool.

But some of the OS kernels are unable to allocate this larger
contiguous block of memory pool.

So, the proposal is to allocate memory independently for each
Reply Queue and pass down all of the addresses to the firmware.
Then the firmware will just take each address and program the value
into the correct register.

When HBAs with older firmware(i.e. without RDPQ capability) is used
with this new driver then the max_msix_vectors value would be set
to 8 by default.

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
---
 drivers/scsi/mpt3sas/mpt3sas_base.c |  916 ++++++++++++++++++++---------------
 drivers/scsi/mpt3sas/mpt3sas_base.h |   19 +-
 2 files changed, 543 insertions(+), 392 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index f1406cc..483785b 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -82,10 +82,10 @@ static int msix_disable = -1;
 module_param(msix_disable, int, 0);
 MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
 
-static int max_msix_vectors = 8;
+static int max_msix_vectors = -1;
 module_param(max_msix_vectors, int, 0);
 MODULE_PARM_DESC(max_msix_vectors,
-	" max msix vectors - (default=8)");
+	" max msix vectors");
 
 static int mpt3sas_fwfault_debug;
 MODULE_PARM_DESC(mpt3sas_fwfault_debug,
@@ -1728,6 +1728,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
 	ioc->reply_queue_count = min_t(int, ioc->cpu_count,
 	    ioc->msix_vector_count);
 
+	if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+		max_msix_vectors = 8;
+
 	printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores"
 	  ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count,
 	  ioc->cpu_count, max_msix_vectors);
@@ -1782,6 +1785,334 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
 }
 
 /**
+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
+ * a write to the doorbell)
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
+ */
+static int
+_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
+	int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 int_status;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		int_status = readl(&ioc->chip->HostInterruptStatus);
+		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+			dhsprintk(ioc, pr_info(MPT3SAS_FMT
+			    "%s: successfull count(%d), timeout(%d)\n",
+			    ioc->name, __func__, count, timeout));
+			return 0;
+		}
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+	pr_err(MPT3SAS_FMT
+	    "%s: failed due to timeout count(%d), int_status(%x)!\n",
+	    ioc->name, __func__, count, int_status);
+	return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
+ * doorbell.
+ */
+static int
+_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout,
+	int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 int_status;
+	u32 doorbell;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		int_status = readl(&ioc->chip->HostInterruptStatus);
+		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
+			dhsprintk(ioc, pr_info(MPT3SAS_FMT
+			    "%s: successfull count(%d), timeout(%d)\n",
+			    ioc->name, __func__, count, timeout));
+			return 0;
+		} else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+			doorbell = readl(&ioc->chip->Doorbell);
+			if ((doorbell & MPI2_IOC_STATE_MASK) ==
+			    MPI2_IOC_STATE_FAULT) {
+				mpt3sas_base_fault_info(ioc , doorbell);
+				return -EFAULT;
+			}
+		} else if (int_status == 0xFFFFFFFF)
+			goto out;
+
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+ out:
+	pr_err(MPT3SAS_FMT
+	     "%s: failed due to timeout count(%d), int_status(%x)!\n",
+	     ioc->name, __func__, count, int_status);
+	return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout,
+	int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 doorbell_reg;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		doorbell_reg = readl(&ioc->chip->Doorbell);
+		if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
+			dhsprintk(ioc, pr_info(MPT3SAS_FMT
+			    "%s: successfull count(%d), timeout(%d)\n",
+			    ioc->name, __func__, count, timeout));
+			return 0;
+		}
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+	pr_err(MPT3SAS_FMT
+	    "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n",
+	    ioc->name, __func__, count, doorbell_reg);
+	return -EFAULT;
+}
+
+/**
+ * _base_handshake_req_reply_wait - send request thru doorbell interface
+ * @ioc: per adapter object
+ * @request_bytes: request length
+ * @request: pointer having request payload
+ * @reply_bytes: reply length
+ * @reply: pointer to reply payload
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
+	u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
+{
+	MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
+	int i;
+	u8 failed;
+	u16 dummy;
+	__le32 *mfp;
+
+	/* make sure doorbell is not in use */
+	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+		pr_err(MPT3SAS_FMT "doorbell is in use (line=%d)\n",
+		    ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* clear pending doorbell interrupts from previous state changes */
+	if (readl(&ioc->chip->HostInterruptStatus) &
+	    MPI2_HIS_IOC2SYS_DB_STATUS)
+		writel(0, &ioc->chip->HostInterruptStatus);
+
+	/* send message to ioc */
+	writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
+	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
+	    &ioc->chip->Doorbell);
+
+	if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
+		pr_err(MPT3SAS_FMT "doorbell handshake int failed (line=%d)\n",
+		   ioc->name, __LINE__);
+		return -EFAULT;
+	}
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
+		pr_err(MPT3SAS_FMT "doorbell handshake ack failed (line=%d)\n",
+		    ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* send message 32-bits at a time */
+	for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
+		writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
+		if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
+			failed = 1;
+	}
+
+	if (failed) {
+		pr_err(MPT3SAS_FMT
+		    "doorbell handshake sending request failed (line=%d)\n ",
+		    ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* now wait for the reply */
+	if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
+		pr_err(MPT3SAS_FMT "doorbell handshake int failed (line=%d)\n",
+		   ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* read the first two 16-bits, it gives the total length of the reply */
+	reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+	    & MPI2_DOORBELL_DATA_MASK);
+	writel(0, &ioc->chip->HostInterruptStatus);
+	if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+		pr_err(MPT3SAS_FMT "doorbell handshake int failed (line=%d)\n",
+		   ioc->name, __LINE__);
+		return -EFAULT;
+	}
+	reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+	    & MPI2_DOORBELL_DATA_MASK);
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	for (i = 2; i < default_reply->MsgLength * 2; i++)  {
+		if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+			pr_err(MPT3SAS_FMT
+			    "doorbell handshake int failed (line=%d)\n",
+			    ioc->name, __LINE__);
+			return -EFAULT;
+		}
+		if (i >=  reply_bytes/2) /* overflow case */
+			dummy = readl(&ioc->chip->Doorbell);
+		else
+			reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+			    & MPI2_DOORBELL_DATA_MASK);
+		writel(0, &ioc->chip->HostInterruptStatus);
+	}
+
+	_base_wait_for_doorbell_int(ioc, 5, sleep_flag);
+	if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
+		dhsprintk(ioc, pr_info(MPT3SAS_FMT"doorbell in use(line=%d)\n",
+		    ioc->name, __LINE__));
+	}
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	if (ioc->logging_level & MPT_DEBUG_INIT) {
+		mfp = (__le32 *)reply;
+		pr_info("\toffset:data\n");
+		for (i = 0; i < reply_bytes/4; i++)
+			pr_info("\t[0x%02x]:%08x\n", i*4,
+			    le32_to_cpu(mfp[i]));
+	}
+	return 0;
+}
+
+/**
+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
+{
+	Mpi2IOCFactsRequest_t mpi_request;
+	Mpi2IOCFactsReply_t mpi_reply;
+	struct mpt3sas_facts *facts;
+	int mpi_reply_sz, mpi_request_sz, r;
+
+	dhsprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+	    __func__));
+
+	mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
+	mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
+	memset(&mpi_request, 0, mpi_request_sz);
+	mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
+	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+	if (r != 0) {
+		pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
+		    ioc->name, __func__, r);
+		return r;
+	}
+
+	facts = &ioc->facts;
+	memset(facts, 0, sizeof(struct mpt3sas_facts));
+	facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
+	facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
+	facts->VP_ID = mpi_reply.VP_ID;
+	facts->VF_ID = mpi_reply.VF_ID;
+	facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
+	facts->MaxChainDepth = mpi_reply.MaxChainDepth;
+	facts->WhoInit = mpi_reply.WhoInit;
+	facts->NumberOfPorts = mpi_reply.NumberOfPorts;
+	facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
+	facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
+	facts->MaxReplyDescriptorPostQueueDepth =
+	    le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
+	facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
+	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
+	if ((facts->IOCCapabilities &
+	     MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
+		ioc->ir_firmware = 1;
+	if ((facts->IOCCapabilities &
+	     MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
+		ioc->rdpq_array_capable = 1;
+	else
+		ioc->rdpq_array_capable = 0;
+	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
+	facts->IOCRequestFrameSize =
+	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+	facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
+	facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
+	ioc->shost->max_id = -1;
+	facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
+	facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
+	facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
+	facts->HighPriorityCredit =
+	    le16_to_cpu(mpi_reply.HighPriorityCredit);
+	facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
+	facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
+
+	dhsprintk(ioc, pr_info(MPT3SAS_FMT
+	    "hba queue depth(%d), max chains per io(%d)\n",
+	    ioc->name, facts->RequestCredit, facts->MaxChainDepth));
+	dhsprintk(ioc, pr_info(MPT3SAS_FMT
+	    "request frame size(%d), reply frame size(%d)\n", ioc->name,
+	    facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
+	return 0;
+}
+
+/**
  * mpt3sas_base_map_resources - map in controller resources (io/irq/memap)
  * @ioc: per adapter object
  *
@@ -1855,6 +2186,16 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
 	}
 
 	_base_mask_interrupts(ioc);
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out_fail;
+
+	if (!ioc->rdpq_array_enable_assigned) {
+		ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+		ioc->rdpq_array_enable_assigned = 1;
+	}
+
 	r = _base_enable_msix(ioc);
 	if (r)
 		goto out_fail;
@@ -2576,15 +2917,36 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
 		ioc->reply_free = NULL;
 	}
 
-	if (ioc->reply_post_free) {
-		pci_pool_free(ioc->reply_post_free_dma_pool,
-		    ioc->reply_post_free, ioc->reply_post_free_dma);
+	if (ioc->reply_post) {
+		if (ioc->rdpq_array_enable) {
+			for (i = 0; i < ioc->reply_queue_count; i++) {
+			     if (ioc->reply_post[i].reply_post_free) {
+				pci_pool_free(
+				  ioc->reply_post_free_dma_pool,
+				  ioc->reply_post[i].reply_post_free,
+				  ioc->reply_post[i].reply_post_free_dma);
+				dexitprintk(ioc, pr_info(MPT3SAS_FMT
+				  "reply_post_free_pool(0x%p): free\n",
+				  ioc->name,
+				  ioc->reply_post[i].reply_post_free));
+				  ioc->reply_post[i].reply_post_free = NULL;
+			     }
+			}
+		} else {
+		   if (ioc->reply_post[0].reply_post_free) {
+			pci_pool_free(ioc->reply_post_free_dma_pool,
+			 ioc->reply_post[0].reply_post_free,
+			 ioc->reply_post[0].reply_post_free_dma);
+			dexitprintk(ioc, pr_info(MPT3SAS_FMT
+			 "reply_post_free_pool(0x%p): free\n", ioc->name,
+			 ioc->reply_post[0].reply_post_free));
+			ioc->reply_post[0].reply_post_free = NULL;
+		  }
+		}
+
 		if (ioc->reply_post_free_dma_pool)
 			pci_pool_destroy(ioc->reply_post_free_dma_pool);
-		dexitprintk(ioc, pr_info(MPT3SAS_FMT
-		    "reply_post_free_pool(0x%p): free\n", ioc->name,
-		    ioc->reply_post_free));
-		ioc->reply_post_free = NULL;
+		kfree(ioc->reply_post);
 	}
 
 	if (ioc->config_page) {
@@ -2945,39 +3307,82 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc,  int sleep_flag)
 		ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
+	if (ioc->rdpq_array_enable) {
+		ioc->reply_post = kcalloc(ioc->reply_queue_count,
+		sizeof(struct reply_post_struct), GFP_KERNEL);
+		/* reply post queue, 16 byte align */
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		sizeof(Mpi2DefaultReplyDescriptor_t);
 		sz = reply_post_free_sz;
-	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-	    ioc->pdev, sz, 16, 0);
-	if (!ioc->reply_post_free_dma_pool) {
-		pr_err(MPT3SAS_FMT
-			"reply_post_free pool: pci_pool_create failed\n",
-			ioc->name);
-		goto out;
-	}
-	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-	    GFP_KERNEL, &ioc->reply_post_free_dma);
-	if (!ioc->reply_post_free) {
-		pr_err(MPT3SAS_FMT
-			"reply_post_free pool: pci_pool_alloc failed\n",
-			ioc->name);
-		goto out;
+		ioc->reply_post_free_dma_pool =
+			pci_pool_create("reply_post_free pool", ioc->pdev, sz,
+			16, 2147483648);
+		if (!ioc->reply_post_free_dma_pool) {
+			pr_err(MPT3SAS_FMT
+			 "reply_post_free pool: pci_pool_create failed\n",
+			 ioc->name);
+			goto out;
+		}
+		for (i = 0; i < ioc->reply_queue_count; i++) {
+			ioc->reply_post[i].reply_post_free =
+				pci_pool_alloc(ioc->reply_post_free_dma_pool,
+				GFP_KERNEL,
+				&ioc->reply_post[i].reply_post_free_dma);
+			if (!ioc->reply_post[i].reply_post_free) {
+				pr_err(MPT3SAS_FMT "reply_post_free pool: "
+					"pci_pool_alloc failed\n", ioc->name);
+				goto out;
+			}
+			memset(ioc->reply_post[i].reply_post_free, 0, sz);
+			dinitprintk(ioc, pr_info(MPT3SAS_FMT
+			 "reply post free pool (0x%p): depth(%d), "
+			 "element_size(%d), pool_size(%d kB)\n",
+			 ioc->name, ioc->reply_post[i].reply_post_free,
+			 ioc->reply_post_queue_depth, 8, sz/1024));
+			dinitprintk(ioc, pr_err(MPT3SAS_FMT
+			 "reply_post_free_dma = (0x%llx)\n", ioc->name,
+			 (unsigned long long)
+			 ioc->reply_post[i].reply_post_free_dma));
+			total_sz += sz;
+		}
+	} else {
+		ioc->reply_post = kzalloc(sizeof(struct reply_post_struct),
+			GFP_KERNEL);
+		/* reply post queue, 16 byte align */
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+			sizeof(Mpi2DefaultReplyDescriptor_t);
+		if (_base_is_controller_msix_enabled(ioc))
+			sz = reply_post_free_sz * ioc->reply_queue_count;
+		else
+			sz = reply_post_free_sz;
+		ioc->reply_post_free_dma_pool =
+			pci_pool_create("reply_post_free pool",
+				ioc->pdev, sz, 16, 0);
+		if (!ioc->reply_post_free_dma_pool) {
+			pr_err(MPT3SAS_FMT
+			 "reply_post_free pool: pci_pool_create failed\n",
+			 ioc->name);
+			goto out;
+		}
+		ioc->reply_post[0].reply_post_free =
+			pci_pool_alloc(ioc->reply_post_free_dma_pool,
+			GFP_KERNEL, &ioc->reply_post[0].reply_post_free_dma);
+		if (!ioc->reply_post[0].reply_post_free) {
+			pr_err(MPT3SAS_FMT
+			 "reply_post_free pool: pci_pool_alloc failed\n",
+			 ioc->name);
+			goto out;
+		}
+		memset(ioc->reply_post[0].reply_post_free, 0, sz);
+		dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply post free pool"
+		 "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+		 ioc->name, ioc->reply_post[0].reply_post_free,
+		 ioc->reply_post_queue_depth, 8, sz/1024));
+		dinitprintk(ioc, pr_info(MPT3SAS_FMT
+		 "reply_post_free_dma = (0x%llx)\n", ioc->name,
+		 (unsigned long long)ioc->reply_post[0].reply_post_free_dma));
+		total_sz += sz;
 	}
-	memset(ioc->reply_post_free, 0, sz);
-	dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply post free pool" \
-	    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-	    ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-	    sz/1024));
-	dinitprintk(ioc, pr_info(MPT3SAS_FMT
-		"reply_post_free_dma = (0x%llx)\n",
-		ioc->name, (unsigned long long)
-	    ioc->reply_post_free_dma));
-	total_sz += sz;
 
 	ioc->config_page_sz = 512;
 	ioc->config_page = pci_alloc_consistent(ioc->pdev,
@@ -3060,138 +3465,6 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
 }
 
 /**
- * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
- * a write to the doorbell)
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
- */
-static int
-_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
-	int sleep_flag)
-{
-	u32 cntdn, count;
-	u32 int_status;
-
-	count = 0;
-	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-	do {
-		int_status = readl(&ioc->chip->HostInterruptStatus);
-		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
-			dhsprintk(ioc, pr_info(MPT3SAS_FMT
-				"%s: successful count(%d), timeout(%d)\n",
-				ioc->name, __func__, count, timeout));
-			return 0;
-		}
-		if (sleep_flag == CAN_SLEEP)
-			usleep_range(1000, 1500);
-		else
-			udelay(500);
-		count++;
-	} while (--cntdn);
-
-	pr_err(MPT3SAS_FMT
-		"%s: failed due to timeout count(%d), int_status(%x)!\n",
-		ioc->name, __func__, count, int_status);
-	return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
- * doorbell.
- */
-static int
-_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout,
-	int sleep_flag)
-{
-	u32 cntdn, count;
-	u32 int_status;
-	u32 doorbell;
-
-	count = 0;
-	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-	do {
-		int_status = readl(&ioc->chip->HostInterruptStatus);
-		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
-			dhsprintk(ioc, pr_info(MPT3SAS_FMT
-				"%s: successful count(%d), timeout(%d)\n",
-				ioc->name, __func__, count, timeout));
-			return 0;
-		} else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
-			doorbell = readl(&ioc->chip->Doorbell);
-			if ((doorbell & MPI2_IOC_STATE_MASK) ==
-			    MPI2_IOC_STATE_FAULT) {
-				mpt3sas_base_fault_info(ioc , doorbell);
-				return -EFAULT;
-			}
-		} else if (int_status == 0xFFFFFFFF)
-			goto out;
-
-		if (sleep_flag == CAN_SLEEP)
-			usleep_range(1000, 1500);
-		else
-			udelay(500);
-		count++;
-	} while (--cntdn);
-
- out:
-	pr_err(MPT3SAS_FMT
-	 "%s: failed due to timeout count(%d), int_status(%x)!\n",
-	 ioc->name, __func__, count, int_status);
-	return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout,
-	int sleep_flag)
-{
-	u32 cntdn, count;
-	u32 doorbell_reg;
-
-	count = 0;
-	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-	do {
-		doorbell_reg = readl(&ioc->chip->Doorbell);
-		if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
-			dhsprintk(ioc, pr_info(MPT3SAS_FMT
-				"%s: successful count(%d), timeout(%d)\n",
-				ioc->name, __func__, count, timeout));
-			return 0;
-		}
-		if (sleep_flag == CAN_SLEEP)
-			usleep_range(1000, 1500);
-		else
-			udelay(500);
-		count++;
-	} while (--cntdn);
-
-	pr_err(MPT3SAS_FMT
-		"%s: failed due to timeout count(%d), doorbell_reg(%x)!\n",
-		ioc->name, __func__, count, doorbell_reg);
-	return -EFAULT;
-}
-
-/**
  * _base_send_ioc_reset - send doorbell reset
  * @ioc: per adapter object
  * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
@@ -3241,129 +3514,6 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout,
 }
 
 /**
- * _base_handshake_req_reply_wait - send request thru doorbell interface
- * @ioc: per adapter object
- * @request_bytes: request length
- * @request: pointer having request payload
- * @reply_bytes: reply length
- * @reply: pointer to reply payload
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
-	u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
-{
-	MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
-	int i;
-	u8 failed;
-	u16 dummy;
-	__le32 *mfp;
-
-	/* make sure doorbell is not in use */
-	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
-		pr_err(MPT3SAS_FMT
-			"doorbell is in use (line=%d)\n",
-			ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* clear pending doorbell interrupts from previous state changes */
-	if (readl(&ioc->chip->HostInterruptStatus) &
-	    MPI2_HIS_IOC2SYS_DB_STATUS)
-		writel(0, &ioc->chip->HostInterruptStatus);
-
-	/* send message to ioc */
-	writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
-	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
-	    &ioc->chip->Doorbell);
-
-	if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
-		pr_err(MPT3SAS_FMT
-			"doorbell handshake int failed (line=%d)\n",
-			ioc->name, __LINE__);
-		return -EFAULT;
-	}
-	writel(0, &ioc->chip->HostInterruptStatus);
-
-	if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
-		pr_err(MPT3SAS_FMT
-			"doorbell handshake ack failed (line=%d)\n",
-			ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* send message 32-bits at a time */
-	for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
-		writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
-		if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
-			failed = 1;
-	}
-
-	if (failed) {
-		pr_err(MPT3SAS_FMT
-			"doorbell handshake sending request failed (line=%d)\n",
-			ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* now wait for the reply */
-	if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
-		pr_err(MPT3SAS_FMT
-			"doorbell handshake int failed (line=%d)\n",
-			ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* read the first two 16-bits, it gives the total length of the reply */
-	reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-	    & MPI2_DOORBELL_DATA_MASK);
-	writel(0, &ioc->chip->HostInterruptStatus);
-	if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
-		pr_err(MPT3SAS_FMT
-			"doorbell handshake int failed (line=%d)\n",
-			ioc->name, __LINE__);
-		return -EFAULT;
-	}
-	reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-	    & MPI2_DOORBELL_DATA_MASK);
-	writel(0, &ioc->chip->HostInterruptStatus);
-
-	for (i = 2; i < default_reply->MsgLength * 2; i++)  {
-		if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
-			pr_err(MPT3SAS_FMT
-				"doorbell handshake int failed (line=%d)\n",
-				ioc->name, __LINE__);
-			return -EFAULT;
-		}
-		if (i >=  reply_bytes/2) /* overflow case */
-			dummy = readl(&ioc->chip->Doorbell);
-		else
-			reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-			    & MPI2_DOORBELL_DATA_MASK);
-		writel(0, &ioc->chip->HostInterruptStatus);
-	}
-
-	_base_wait_for_doorbell_int(ioc, 5, sleep_flag);
-	if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
-		dhsprintk(ioc, pr_info(MPT3SAS_FMT
-			"doorbell is in use (line=%d)\n", ioc->name, __LINE__));
-	}
-	writel(0, &ioc->chip->HostInterruptStatus);
-
-	if (ioc->logging_level & MPT_DEBUG_INIT) {
-		mfp = (__le32 *)reply;
-		pr_info("\toffset:data\n");
-		for (i = 0; i < reply_bytes/4; i++)
-			pr_info("\t[0x%02x]:%08x\n", i*4,
-			    le32_to_cpu(mfp[i]));
-	}
-	return 0;
-}
-
-/**
  * mpt3sas_base_sas_iounit_control - send sas iounit control to FW
  * @ioc: per adapter object
  * @mpi_reply: the reply payload from FW
@@ -3613,79 +3763,6 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag)
 }
 
 /**
- * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
-{
-	Mpi2IOCFactsRequest_t mpi_request;
-	Mpi2IOCFactsReply_t mpi_reply;
-	struct mpt3sas_facts *facts;
-	int mpi_reply_sz, mpi_request_sz, r;
-
-	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
-	    __func__));
-
-	mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
-	mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
-	memset(&mpi_request, 0, mpi_request_sz);
-	mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
-	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
-	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
-
-	if (r != 0) {
-		pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
-		    ioc->name, __func__, r);
-		return r;
-	}
-
-	facts = &ioc->facts;
-	memset(facts, 0, sizeof(struct mpt3sas_facts));
-	facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
-	facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
-	facts->VP_ID = mpi_reply.VP_ID;
-	facts->VF_ID = mpi_reply.VF_ID;
-	facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
-	facts->MaxChainDepth = mpi_reply.MaxChainDepth;
-	facts->WhoInit = mpi_reply.WhoInit;
-	facts->NumberOfPorts = mpi_reply.NumberOfPorts;
-	facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
-	facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
-	facts->MaxReplyDescriptorPostQueueDepth =
-	    le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
-	facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
-	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
-	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
-		ioc->ir_firmware = 1;
-	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
-	facts->IOCRequestFrameSize =
-	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
-	facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
-	facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
-	ioc->shost->max_id = -1;
-	facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
-	facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
-	facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
-	facts->HighPriorityCredit =
-	    le16_to_cpu(mpi_reply.HighPriorityCredit);
-	facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
-	facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
-
-	dinitprintk(ioc, pr_info(MPT3SAS_FMT
-		"hba queue depth(%d), max chains per io(%d)\n",
-		ioc->name, facts->RequestCredit,
-	    facts->MaxChainDepth));
-	dinitprintk(ioc, pr_info(MPT3SAS_FMT
-		"request frame size(%d), reply frame size(%d)\n", ioc->name,
-	    facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
-	return 0;
-}
-
-/**
  * _base_send_ioc_init - send ioc_init to firmware
  * @ioc: per adapter object
  * @sleep_flag: CAN_SLEEP or NO_SLEEP
@@ -3697,9 +3774,13 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 {
 	Mpi2IOCInitRequest_t mpi_request;
 	Mpi2IOCInitReply_t mpi_reply;
-	int r;
+	int i, r = 0;
 	struct timeval current_time;
 	u16 ioc_status;
+	u32 reply_post_free_array_sz;
+	Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+	dma_addr_t reply_post_free_array_dma;
+	struct dma_pool *reply_post_free_array_dma_pool = NULL;
 
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
 	    __func__));
@@ -3728,9 +3809,39 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 	    cpu_to_le64((u64)ioc->request_dma);
 	mpi_request.ReplyFreeQueueAddress =
 	    cpu_to_le64((u64)ioc->reply_free_dma);
-	mpi_request.ReplyDescriptorPostQueueAddress =
-	    cpu_to_le64((u64)ioc->reply_post_free_dma);
 
+	if (ioc->rdpq_array_enable) {
+		reply_post_free_array_sz = ioc->reply_queue_count *
+		    sizeof(Mpi2IOCInitRDPQArrayEntry);
+		reply_post_free_array_dma_pool =
+		    pci_pool_create("reply_post_free_array pool",
+		    ioc->pdev, reply_post_free_array_sz, 16, 0);
+		if (!reply_post_free_array_dma_pool) {
+			pr_err(MPT3SAS_FMT "reply_post_free_array pool: "
+			    "pci_pool_create failed\n", ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+		reply_post_free_array =
+		    pci_pool_alloc(reply_post_free_array_dma_pool,
+		    GFP_KERNEL, &reply_post_free_array_dma);
+		if (!reply_post_free_array) {
+			pr_err(MPT3SAS_FMT "reply_post_free_array pool: "
+			    "pci_pool_alloc failed\n", ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+		memset(reply_post_free_array, 0, reply_post_free_array_sz);
+		for (i = 0; i < ioc->reply_queue_count; i++)
+			reply_post_free_array[i].RDPQBaseAddress =
+		      cpu_to_le64((u64)ioc->reply_post[i].reply_post_free_dma);
+		mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)reply_post_free_array_dma);
+	} else {
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
+	}
 
 	/* This time stamp specifies number of milliseconds
 	 * since epoch ~ midnight January 1, 1970.
@@ -3758,7 +3869,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 	if (r != 0) {
 		pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
 		    ioc->name, __func__, r);
-		return r;
+		goto out;
 	}
 
 	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3767,8 +3878,17 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 		pr_err(MPT3SAS_FMT "%s: failed\n", ioc->name, __func__);
 		r = -EIO;
 	}
-
-	return 0;
+out:
+	if (ioc->rdpq_array_enable) {
+		if (reply_post_free_array) {
+			pci_pool_free(reply_post_free_array_dma_pool,
+			   reply_post_free_array, reply_post_free_array_dma);
+			reply_post_free_array = NULL;
+		}
+		if (reply_post_free_array_dma_pool)
+			pci_pool_destroy(reply_post_free_array_dma_pool);
+	}
+	return r;
 }
 
 /**
@@ -4311,7 +4431,7 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
 static int
 _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 {
-	int r, i;
+	int r, i, j = 0;
 	unsigned long	flags;
 	u32 reply_address;
 	u16 smid;
@@ -4389,19 +4509,32 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 		_base_assign_reply_queues(ioc);
 
 	/* initialize Reply Post Free Queue */
-	reply_post_free = (long)ioc->reply_post_free;
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-		reply_q->reply_post_host_index = 0;
-		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
-		    reply_post_free;
-		for (i = 0; i < ioc->reply_post_queue_depth; i++)
-			reply_q->reply_post_free[i].Words =
-			    cpu_to_le64(ULLONG_MAX);
-		if (!_base_is_controller_msix_enabled(ioc))
-			goto skip_init_reply_post_free_queue;
-		reply_post_free += reply_post_free_sz;
+	if (ioc->rdpq_array_enable) {
+		list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+			reply_q->reply_post_host_index = 0;
+			reply_q->reply_post_free =
+			    ioc->reply_post[j++].reply_post_free;
+			for (i = 0; i < ioc->reply_post_queue_depth; i++)
+				reply_q->reply_post_free[i].Words =
+				    cpu_to_le64(ULLONG_MAX);
+			if (!_base_is_controller_msix_enabled(ioc))
+				goto skip_init_reply_post_free_queue;
+		}
+	} else {
+		reply_post_free = (long)ioc->reply_post[0].reply_post_free;
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		    sizeof(Mpi2DefaultReplyDescriptor_t);
+		list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+			reply_q->reply_post_host_index = 0;
+			reply_q->reply_post_free =
+			    (Mpi2ReplyDescriptorsUnion_t *)reply_post_free;
+			for (i = 0; i < ioc->reply_post_queue_depth; i++)
+				reply_q->reply_post_free[i].Words =
+				    cpu_to_le64(ULLONG_MAX);
+			if (!_base_is_controller_msix_enabled(ioc))
+				goto skip_init_reply_post_free_queue;
+			reply_post_free += reply_post_free_sz;
+		}
 	}
  skip_init_reply_post_free_queue:
 
@@ -4512,6 +4645,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
 		goto out_free_resources;
 	}
 
+	ioc->rdpq_array_enable_assigned = 0;
 	r = mpt3sas_base_map_resources(ioc);
 	if (r)
 		goto out_free_resources;
@@ -4888,6 +5022,12 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
 	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
 	if (r)
 		goto out;
+
+	if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+		panic("%s: Issue occurred with flashing controller firmware. "
+			"Please reboot the system and ensure that the correct"
+			" firmware version is running\n", ioc->name);
+
 	r = _base_make_ioc_operational(ioc, sleep_flag);
 	if (!r)
 		_base_reset_handler(ioc, MPT3_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index f61765c..8fb2a38 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -569,6 +569,12 @@ struct mpt3sas_port_facts {
 	u16			MaxPostedCmdBuffers;
 };
 
+struct reply_post_struct {
+	Mpi2ReplyDescriptorsUnion_t     *reply_post_free;
+	dma_addr_t                      reply_post_free_dma;
+};
+
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
@@ -712,8 +718,11 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned:this ensures that rdpq_array_enable flag
+ *				is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -915,11 +924,13 @@ struct MPT3SAS_ADAPTER {
 
 	/* reply post queue */
 	u16		reply_post_queue_depth;
-	Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-	dma_addr_t	reply_post_free_dma;
+	struct reply_post_struct *reply_post;
 	struct dma_pool *reply_post_free_dma_pool;
 	u8		reply_queue_count;
 	struct list_head reply_queue_list;
+	u8              rdpq_array_capable;
+	u8              rdpq_array_enable;
+	u8              rdpq_array_enable_assigned;
 
 	struct list_head delayed_tr_list;
 	struct list_head delayed_tr_volume_list;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RESEND][PATCH 7/8][SCSI]mpt3sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-06-25 10:41 [RESEND][PATCH 7/8][SCSI]mpt3sas: Added Reply Descriptor Post Queue (RDPQ) Array support Reddy, Sreekanth
@ 2014-08-05 15:24 ` Tomas Henzl
       [not found]   ` <CAK=zhgqBfFpUJ1FTQGNKoGnLBBsX=6AGwr14DZVNjdAjihY0sw@mail.gmail.com>
  0 siblings, 1 reply; 4+ messages in thread
From: Tomas Henzl @ 2014-08-05 15:24 UTC (permalink / raw)
  To: Reddy, Sreekanth, jejb, JBottomley
  Cc: linux-scsi, Sathya.Prakash, Nagalakshmi.Nandigama, linux-kernel,
	hch, martin.petersen

On 06/25/2014 12:41 PM, Reddy, Sreekanth wrote:
> Up to now, Driver allocates a single contiguous block of memory
> pool for all reply queues and passes down a single address in the
> ReplyDescriptorPostQueueAddress field of the IOC Init Request
> Message to the firmware.
>
> When firmware receives this address, it will program each of the
> Reply Descriptor Post Queue registers, as each reply queue has its
> own register. Thus the firmware, starting from a base address it
> determines the starting address of the subsequent reply queues
> through some simple arithmetic calculations.
>
> The size of this contiguous block of memory pool is directly proportional
> to number of MSI-X vectors and the HBA queue depth. For example higher
> MSIX vectors requires larger contiguous block of memory pool.
>
> But some of the OS kernels are unable to allocate this larger
> contiguous block of memory pool.
>
> So, the proposal is to allocate memory independently for each
> Reply Queue and pass down all of the addresses to the firmware.
> Then the firmware will just take each address and program the value
> into the correct register.
>
> When HBAs with older firmware(i.e. without RDPQ capability) is used
> with this new driver then the max_msix_vectors value would be set
> to 8 by default.
>
> Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
> ---
>  drivers/scsi/mpt3sas/mpt3sas_base.c |  916 ++++++++++++++++++++---------------
>  drivers/scsi/mpt3sas/mpt3sas_base.h |   19 +-
>  2 files changed, 543 insertions(+), 392 deletions(-)
>
...
> +static int
> +_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
> +	u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
> +{
> +	MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
> +	int i;
> +	u8 failed;
> +	u16 dummy;
> +	__le32 *mfp;
> +
> +	/* make sure doorbell is not in use */
> +	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {

	if (readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED) {
I think it's equal and better looking with less parentheses, but 
it's a personal preference so you can ignore it.

> +		pr_err(MPT3SAS_FMT "doorbell is in use (line=%d)\n",
> +		    ioc->name, __LINE__);
> +		return -EFAULT;
> +	}
> +
> +	/* clear pending doorbell interrupts from previous state changes */
> +	if (readl(&ioc->chip->HostInterruptStatus) &
> +	    MPI2_HIS_IOC2SYS_DB_STATUS)
> +		writel(0, &ioc->chip->HostInterruptStatus);
> +
> +	/* send message to ioc */
> +	writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
> +	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
> +	    &ioc->chip->Doorbell);
> +
> +	if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {

Most likely not a problem, but why NO_SLEEP and not the sleep_flag ?

> +		pr_err(MPT3SAS_FMT "doorbell handshake int failed (line=%d)\n",
> +		   ioc->name, __LINE__);
> +		return -EFAULT;
> +	}
> +	writel(0, &ioc->chip->HostInterruptStatus);
> +
> +	if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
> +		pr_err(MPT3SAS_FMT "doorbell handshake ack failed (line=%d)\n",
> +		    ioc->name, __LINE__);
> +		return -EFAULT;
> +	}
> +
> +	/* send message 32-bits at a time */
> +	for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
> +		writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
> +		if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
> +			failed = 1;
> +	}
...

@@ -2945,39 +3307,82 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc,  int sleep_flag)
 		ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
+	if (ioc->rdpq_array_enable) {
+		ioc->reply_post = kcalloc(ioc->reply_queue_count,
+		sizeof(struct reply_post_struct), GFP_KERNEL);
+		/* reply post queue, 16 byte align */
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		sizeof(Mpi2DefaultReplyDescriptor_t);
 		sz = reply_post_free_sz;
-	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-	    ioc->pdev, sz, 16, 0);
-	if (!ioc->reply_post_free_dma_pool) {
-		pr_err(MPT3SAS_FMT
-			"reply_post_free pool: pci_pool_create failed\n",
-			ioc->name);
-		goto out;
-	}
-	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-	    GFP_KERNEL, &ioc->reply_post_free_dma);
-	if (!ioc->reply_post_free) {
-		pr_err(MPT3SAS_FMT
-			"reply_post_free pool: pci_pool_alloc failed\n",
-			ioc->name);
-		goto out;
+		ioc->reply_post_free_dma_pool =
+			pci_pool_create("reply_post_free pool", ioc->pdev, sz,
+			16, 2147483648);

Few lines below with older firmware you don't need this rather
high boundary of 2^31, why is it needed here?

Besides that, checkpatch shows 11 warnings and some of them might be functional - 
"WARNING: msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers"
please clean your patch next time.

Cheers,
Tomas


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [RESEND][PATCH 7/8][SCSI]mpt3sas: Added Reply Descriptor Post Queue (RDPQ) Array support
       [not found]   ` <CAK=zhgqBfFpUJ1FTQGNKoGnLBBsX=6AGwr14DZVNjdAjihY0sw@mail.gmail.com>
@ 2014-08-06 15:56     ` Tomas Henzl
  0 siblings, 0 replies; 4+ messages in thread
From: Tomas Henzl @ 2014-08-06 15:56 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: jejb, James E.J. Bottomley, linux-scsi, Sathya Prakash,
	Nagalakshmi Nandigama, linux-kernel, Christoph Hellwig,
	Martin K. Petersen

On 08/05/2014 06:41 PM, Sreekanth Reddy wrote:
> Hi Tomas,
>
> Can you please review this updated patch,

Hi Sreekanth,
the patch is mangled so a resend is needed anyway and I think you will
probably also want implement the changes you were asked for in the
mpt2sas sibling of this patch.
Thanks, Tomas

>
> Up to now, Driver allocates a single contiguous block of memory
> pool for all reply queues and passes down a single address in the
> ReplyDescriptorPostQueueAddress field of the IOC Init Request
> Message to the firmware.
>
> When firmware receives this address, it will program each of the
> Reply Descriptor Post Queue registers, as each reply queue has its
> own register. Thus the firmware, starting from a base address it
> determines the starting address of the subsequent reply queues
> through some simple arithmetic calculations.
>
> The size of this contiguous block of memory pool is directly proportional
> to number of MSI-X vectors and the HBA queue depth. For example higher
> MSIX vectors requires larger contiguous block of memory pool.
>
> But some of the OS kernels are unable to allocate this larger
> contiguous block of memory pool.
>
> So, the proposal is to allocate memory independently for each
> Reply Queue and pass down all of the addresses to the firmware.
> Then the firmware will just take each address and program the value
> into the correct register.
>
> When HBAs with older firmware(i.e. without RDPQ capability) is used
> with this new driver then the max_msix_vectors value would be set
> to 8 by default.
>
> Change set in v2:
>
> 1. Declared the following functions at the beginning of the mpt3sas_base.c
> file instead of moving all these functions before
> mpt3sas_base_map_resources() function
>         a. _base_wait_for_doorbell_int()
>         b. _base_wait_for_doorbell_ack()
>         c. _base_wait_for_doorbell_not_used()
>         d. _base_handshake_req_reply_wait()
>         e. _base_get_ioc_facts()
>
> 2. Initially set the consistent DMA mask to 32 bit and then change it to 64
> bit mask after allocating RDPQ pools by calling the function
> _base_change_consistent_dma_mask. This is to ensure that all the upper 32
> bits of RDPQ entries's base address to be same.
>
> 3. Reduced the redundancy between the RDPQ and non-RDPQ support in these
> following functions
>         a. _base_release_memory_pools()
>         b. _base_allocate_memory_pools()
>         c. _base_send_ioc_init()
>         d. _base_make_ioc_operational()
>
> Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
> ---
>  drivers/scsi/mpt3sas/mpt3sas_base.c | 246
> ++++++++++++++++++++++++++++--------
>  drivers/scsi/mpt3sas/mpt3sas_base.h |  18 ++-
>  2 files changed, 204 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c
> b/drivers/scsi/mpt3sas/mpt3sas_base.c
> index 153b2c1..20c2c7b 100644
> --- a/drivers/scsi/mpt3sas/mpt3sas_base.c
> +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
> @@ -92,6 +92,22 @@ MODULE_PARM_DESC(mpt3sas_fwfault_debug,
>      " enable detection of firmware fault and halt firmware - (default=0)");
>
>
> +static int dma_mask;
> +
> +static int
> +_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout,
> +                int sleep_flag);
> +static int
> +_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout,
> +                int sleep_flag);
> +static int
> +_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout,
> +                 int sleep_flag);
> +static int
> +_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int
> request_bytes,
> +    u32 *request, int reply_bytes, u16 *reply, int timeout, int
> sleep_flag);
> +static int
> +_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag);
>  /**
>   * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
>   *
> @@ -1482,17 +1498,23 @@ static int
>  _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev
> *pdev)
>  {
>      struct sysinfo s;
> -    char *desc = NULL;
> +    u64 consistent_dma_mask;
> +
> +    if (dma_mask)
> +        consistent_dma_mask = DMA_BIT_MASK(64);
> +    else
> +        consistent_dma_mask = DMA_BIT_MASK(32);
>
>      if (sizeof(dma_addr_t) > 4) {
>          const uint64_t required_mask =
>              dma_get_required_mask(&pdev->dev);
>          if ((required_mask > DMA_BIT_MASK(32)) &&
>              !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
> -            !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
> +            !pci_set_consistent_dma_mask(pdev,
> +              DMA_BIT_MASK(consistent_dma_mask))) {
>              ioc->base_add_sg_single = &_base_add_sg_single_64;
>              ioc->sge_size = sizeof(Mpi2SGESimple64_t);
> -            desc = "64";
> +            dma_mask = 64;
>              goto out;
>          }
>      }
> @@ -1501,19 +1523,30 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER
> *ioc, struct pci_dev *pdev)
>          && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
>          ioc->base_add_sg_single = &_base_add_sg_single_32;
>          ioc->sge_size = sizeof(Mpi2SGESimple32_t);
> -        desc = "32";
> +        dma_mask = 32;
>      } else
>          return -ENODEV;
>
>   out:
>      si_meminfo(&s);
>      pr_info(MPT3SAS_FMT
> -        "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
> -        ioc->name, desc, convert_to_kb(s.totalram));
> +        "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
> +        ioc->name, dma_mask, convert_to_kb(s.totalram));
>
>      return 0;
>  }
>
> +static int
> +_base_change_consistent_dma_mask(struct MPT3SAS_ADAPTER *ioc,
> +                      struct pci_dev *pdev)
> +{
> +    if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
> +        if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
> +            return -ENODEV;
> +    }
> +    return 0;
> +}
> +
>  /**
>   * _base_check_enable_msix - checks MSIX capabable.
>   * @ioc: per adapter object
> @@ -1729,6 +1762,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
>        ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count,
>        ioc->cpu_count, max_msix_vectors);
>
> +    if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
> +        max_msix_vectors = 8;
> +
>      if (max_msix_vectors > 0) {
>          ioc->reply_queue_count = min_t(int, max_msix_vectors,
>              ioc->reply_queue_count);
> @@ -1852,6 +1888,16 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER
> *ioc)
>      }
>
>      _base_mask_interrupts(ioc);
> +
> +    r = _base_get_ioc_facts(ioc, CAN_SLEEP);
> +    if (r)
> +        goto out_fail;
> +
> +    if (!ioc->rdpq_array_enable_assigned) {
> +        ioc->rdpq_array_enable = ioc->rdpq_array_capable;
> +        ioc->rdpq_array_enable_assigned = 1;
> +    }
> +
>      r = _base_enable_msix(ioc);
>      if (r)
>          goto out_fail;
> @@ -2527,7 +2573,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
>  static void
>  _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
>  {
> -    int i;
> +    int i = 0;
> +    struct reply_post_struct *rps;
>
>      dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
>          __func__));
> @@ -2572,15 +2619,25 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER
> *ioc)
>          ioc->reply_free = NULL;
>      }
>
> -    if (ioc->reply_post_free) {
> -        pci_pool_free(ioc->reply_post_free_dma_pool,
> -            ioc->reply_post_free, ioc->reply_post_free_dma);
> +    if (ioc->reply_post) {
> +        do {
> +            rps = &ioc->reply_post[i];
> +            if (rps->reply_post_free) {
> +                pci_pool_free(
> +                    ioc->reply_post_free_dma_pool,
> +                    rps->reply_post_free,
> +                    rps->reply_post_free_dma);
> +                dexitprintk(ioc, pr_info(MPT3SAS_FMT
> +                    "reply_post_free_pool(0x%p): free\n",
> +                    ioc->name, rps->reply_post_free));
> +                rps->reply_post_free = NULL;
> +            }
> +        } while (ioc->rdpq_array_enable &&
> +               (++i < ioc->reply_queue_count));
> +
>          if (ioc->reply_post_free_dma_pool)
>              pci_pool_destroy(ioc->reply_post_free_dma_pool);
> -        dexitprintk(ioc, pr_info(MPT3SAS_FMT
> -            "reply_post_free_pool(0x%p): free\n", ioc->name,
> -            ioc->reply_post_free));
> -        ioc->reply_post_free = NULL;
> +        kfree(ioc->reply_post);
>      }
>
>      if (ioc->config_page) {
> @@ -2727,6 +2784,69 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER
> *ioc,  int sleep_flag)
>          ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
>          ioc->chains_needed_per_io));
>
> +    /* reply post queue, 16 byte align */
> +    reply_post_free_sz = ioc->reply_post_queue_depth *
> +        sizeof(Mpi2DefaultReplyDescriptor_t);
> +    if (ioc->rdpq_array_enable)
> +        sz = reply_post_free_sz;
> +    else {
> +        if (_base_is_controller_msix_enabled(ioc))
> +            sz = reply_post_free_sz * ioc->reply_queue_count;
> +        else
> +            sz = reply_post_free_sz;
> +    }
> +
> +    ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
> +        (ioc->reply_queue_count):1,
> +        sizeof(struct reply_post_struct), GFP_KERNEL);
> +
> +    if (!ioc->reply_post) {
> +        pr_err(MPT3SAS_FMT "reply_post_free pool: kcalloc failed\n",
> +            ioc->name);
> +        goto out;
> +    }
> +    ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
> +        ioc->pdev, sz, 16, 0);
> +    if (!ioc->reply_post_free_dma_pool) {
> +        pr_err(MPT3SAS_FMT
> +         "reply_post_free pool: pci_pool_create failed\n",
> +         ioc->name);
> +        goto out;
> +    }
> +    i = 0;
> +    do {
> +        ioc->reply_post[i].reply_post_free =
> +            pci_pool_alloc(ioc->reply_post_free_dma_pool,
> +            GFP_KERNEL,
> +            &ioc->reply_post[i].reply_post_free_dma);
> +        if (!ioc->reply_post[i].reply_post_free) {
> +            pr_err(MPT3SAS_FMT
> +            "reply_post_free pool: pci_pool_alloc failed\n",
> +            ioc->name);
> +            goto out;
> +        }
> +        memset(ioc->reply_post[i].reply_post_free, 0, sz);
> +        dinitprintk(ioc, pr_info(MPT3SAS_FMT
> +            "reply post free pool (0x%p): depth(%d),"
> +            "element_size(%d), pool_size(%d kB)\n", ioc->name,
> +            ioc->reply_post[i].reply_post_free,
> +            ioc->reply_post_queue_depth, 8, sz/1024));
> +        dinitprintk(ioc, pr_info(MPT3SAS_FMT
> +            "reply_post_free_dma = (0x%llx)\n", ioc->name,
> +            (unsigned long long)
> +            ioc->reply_post[i].reply_post_free_dma));
> +        total_sz += sz;
> +    } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
> +
> +    if (dma_mask == 64) {
> +        if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
> +            pr_warn(MPT3SAS_FMT
> +                "no suitable consistent DMA mask for %s\n",
> +                ioc->name, pci_name(ioc->pdev));
> +            goto out;
> +        }
> +    }
> +
>      ioc->scsiio_depth = ioc->hba_queue_depth -
>          ioc->hi_priority_depth - ioc->internal_depth;
>
> @@ -2941,40 +3061,6 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER
> *ioc,  int sleep_flag)
>          ioc->name, (unsigned long long)ioc->reply_free_dma));
>      total_sz += sz;
>
> -    /* reply post queue, 16 byte align */
> -    reply_post_free_sz = ioc->reply_post_queue_depth *
> -        sizeof(Mpi2DefaultReplyDescriptor_t);
> -    if (_base_is_controller_msix_enabled(ioc))
> -        sz = reply_post_free_sz * ioc->reply_queue_count;
> -    else
> -        sz = reply_post_free_sz;
> -    ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
> -        ioc->pdev, sz, 16, 0);
> -    if (!ioc->reply_post_free_dma_pool) {
> -        pr_err(MPT3SAS_FMT
> -            "reply_post_free pool: pci_pool_create failed\n",
> -            ioc->name);
> -        goto out;
> -    }
> -    ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
> -        GFP_KERNEL, &ioc->reply_post_free_dma);
> -    if (!ioc->reply_post_free) {
> -        pr_err(MPT3SAS_FMT
> -            "reply_post_free pool: pci_pool_alloc failed\n",
> -            ioc->name);
> -        goto out;
> -    }
> -    memset(ioc->reply_post_free, 0, sz);
> -    dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply post free pool" \
> -        "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
> -        ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
> -        sz/1024));
> -    dinitprintk(ioc, pr_info(MPT3SAS_FMT
> -        "reply_post_free_dma = (0x%llx)\n",
> -        ioc->name, (unsigned long long)
> -        ioc->reply_post_free_dma));
> -    total_sz += sz;
> -
>      ioc->config_page_sz = 512;
>      ioc->config_page = pci_alloc_consistent(ioc->pdev,
>          ioc->config_page_sz, &ioc->config_page_dma);
> @@ -3657,6 +3743,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int
> sleep_flag)
>      facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
>      if ((facts->IOCCapabilities &
> MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
>          ioc->ir_firmware = 1;
> +    if ((facts->IOCCapabilities &
> +          MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
> +        ioc->rdpq_array_capable = 1;
>      facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
>      facts->IOCRequestFrameSize =
>          le16_to_cpu(mpi_reply.IOCRequestFrameSize);
> @@ -3693,9 +3782,12 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int
> sleep_flag)
>  {
>      Mpi2IOCInitRequest_t mpi_request;
>      Mpi2IOCInitReply_t mpi_reply;
> -    int r;
> +    int i, r = 0;
>      struct timeval current_time;
>      u16 ioc_status;
> +    u32 reply_post_free_array_sz = 0;
> +    Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
> +    dma_addr_t reply_post_free_array_dma;
>
>      dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
>          __func__));
> @@ -3724,9 +3816,31 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int
> sleep_flag)
>          cpu_to_le64((u64)ioc->request_dma);
>      mpi_request.ReplyFreeQueueAddress =
>          cpu_to_le64((u64)ioc->reply_free_dma);
> -    mpi_request.ReplyDescriptorPostQueueAddress =
> -        cpu_to_le64((u64)ioc->reply_post_free_dma);
>
> +    if (ioc->rdpq_array_enable) {
> +        reply_post_free_array_sz = ioc->reply_queue_count *
> +            sizeof(Mpi2IOCInitRDPQArrayEntry);
> +        reply_post_free_array = pci_alloc_consistent(ioc->pdev,
> +            reply_post_free_array_sz, &reply_post_free_array_dma);
> +        if (!reply_post_free_array) {
> +            pr_err(MPT3SAS_FMT
> +            "reply_post_free_array: pci_alloc_consistent failed\n",
> +            ioc->name);
> +            r = -ENOMEM;
> +            goto out;
> +        }
> +        memset(reply_post_free_array, 0, reply_post_free_array_sz);
> +        for (i = 0; i < ioc->reply_queue_count; i++)
> +            reply_post_free_array[i].RDPQBaseAddress =
> +                cpu_to_le64(
> +                (u64)ioc->reply_post[i].reply_post_free_dma);
> +        mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
> +        mpi_request.ReplyDescriptorPostQueueAddress =
> +            cpu_to_le64((u64)reply_post_free_array_dma);
> +    } else {
> +        mpi_request.ReplyDescriptorPostQueueAddress =
> +            cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
> +    }
>
>      /* This time stamp specifies number of milliseconds
>       * since epoch ~ midnight January 1, 1970.
> @@ -3754,7 +3868,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int
> sleep_flag)
>      if (r != 0) {
>          pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
>              ioc->name, __func__, r);
> -        return r;
> +        goto out;
>      }
>
>      ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
> @@ -3764,7 +3878,12 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int
> sleep_flag)
>          r = -EIO;
>      }
>
> -    return 0;
> +out:
> +    if (reply_post_free_array)
> +        pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
> +                    reply_post_free_array,
> +                    reply_post_free_array_dma);
> +    return r;
>  }
>
>  /**
> @@ -4314,7 +4433,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER
> *ioc, int sleep_flag)
>      struct _tr_list *delayed_tr, *delayed_tr_next;
>      struct adapter_reply_queue *reply_q;
>      long reply_post_free;
> -    u32 reply_post_free_sz;
> +    u32 reply_post_free_sz, index = 0;
>
>      dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
>          __func__));
> @@ -4385,9 +4504,9 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER
> *ioc, int sleep_flag)
>          _base_assign_reply_queues(ioc);
>
>      /* initialize Reply Post Free Queue */
> -    reply_post_free = (long)ioc->reply_post_free;
>      reply_post_free_sz = ioc->reply_post_queue_depth *
>          sizeof(Mpi2DefaultReplyDescriptor_t);
> +    reply_post_free = (long)ioc->reply_post[index].reply_post_free;
>      list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
>          reply_q->reply_post_host_index = 0;
>          reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
> @@ -4397,7 +4516,15 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER
> *ioc, int sleep_flag)
>                  cpu_to_le64(ULLONG_MAX);
>          if (!_base_is_controller_msix_enabled(ioc))
>              goto skip_init_reply_post_free_queue;
> -        reply_post_free += reply_post_free_sz;
> +        /*
> +         * If RDPQ is enabled, switch to the next allocation.
> +         * Otherwise advance within the contiguous region.
> +         */
> +        if (ioc->rdpq_array_enable)
> +            reply_post_free = (long)
> +                ioc->reply_post[++index].reply_post_free;
> +        else
> +            reply_post_free += reply_post_free_sz;
>      }
>   skip_init_reply_post_free_queue:
>
> @@ -4508,6 +4635,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
>          goto out_free_resources;
>      }
>
> +    ioc->rdpq_array_enable_assigned = 0;
>      r = mpt3sas_base_map_resources(ioc);
>      if (r)
>          goto out_free_resources;
> @@ -4884,6 +5012,12 @@ mpt3sas_base_hard_reset_handler(struct
> MPT3SAS_ADAPTER *ioc, int sleep_flag,
>      r = _base_get_ioc_facts(ioc, CAN_SLEEP);
>      if (r)
>          goto out;
> +
> +    if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
> +        panic("%s: Issue occurred with flashing controller firmware."
> +              "Please reboot the system and ensure that the correct"
> +              "firmware version is running\n", ioc->name);
> +
>      r = _base_make_ioc_operational(ioc, sleep_flag);
>      if (!r)
>          _base_reset_handler(ioc, MPT3_IOC_DONE_RESET);
> diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h
> b/drivers/scsi/mpt3sas/mpt3sas_base.h
> index ae97f46..fd5d505 100644
> --- a/drivers/scsi/mpt3sas/mpt3sas_base.h
> +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
> @@ -569,6 +569,11 @@ struct mpt3sas_port_facts {
>      u16            MaxPostedCmdBuffers;
>  };
>
> +struct reply_post_struct {
> +    Mpi2ReplyDescriptorsUnion_t    *reply_post_free;
> +    dma_addr_t            reply_post_free_dma;
> +};
> +
>  /**
>   * enum mutex_type - task management mutex type
>   * @TM_MUTEX_OFF: mutex is not required becuase calling function is
> acquiring it
> @@ -712,8 +717,11 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct
> MPT3SAS_ADAPTER *ioc);
>   * @reply_free_dma_pool:
>   * @reply_free_host_index: tail index in pool to insert free replys
>   * @reply_post_queue_depth: reply post queue depth
> - * @reply_post_free: pool for reply post (64bit descriptor)
> - * @reply_post_free_dma:
> + * @reply_post_struct: struct for reply_post_free physical & virt address
> + * @rdpq_array_capable: FW supports multiple reply queue addresses in
> ioc_init
> + * @rdpq_array_enable: rdpq_array support is enabled in the driver
> + * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
> + *                is assigned only ones
>   * @reply_queue_count: number of reply queue's
>   * @reply_queue_list: link list contaning the reply queue info
>   * @reply_post_host_index: head index in the pool where FW completes IO
> @@ -914,8 +922,10 @@ struct MPT3SAS_ADAPTER {
>
>      /* reply post queue */
>      u16        reply_post_queue_depth;
> -    Mpi2ReplyDescriptorsUnion_t *reply_post_free;
> -    dma_addr_t    reply_post_free_dma;
> +    struct reply_post_struct *reply_post;
> +    u8        rdpq_array_capable;
> +    u8        rdpq_array_enable;
> +    u8        rdpq_array_enable_assigned;
>      struct dma_pool *reply_post_free_dma_pool;
>      u8        reply_queue_count;
>      struct list_head reply_queue_list;


^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [RESEND][PATCH 7/8][SCSI]mpt3sas: Added Reply Descriptor Post Queue (RDPQ) Array support
@ 2014-08-12  9:34 Sreekanth Reddy
  0 siblings, 0 replies; 4+ messages in thread
From: Sreekanth Reddy @ 2014-08-12  9:34 UTC (permalink / raw)
  To: martin.petersen, jejb
  Cc: linux-scsi, JBottomley, Sathya.Prakash, Nagalakshmi.Nandigama,
	linux-kernel, hch, Sreekanth Reddy

Sending this patch once again using git send-email.

Up to now, Driver allocates a single contiguous block of memory
pool for all reply queues and passes down a single address in the
ReplyDescriptorPostQueueAddress field of the IOC Init Request
Message to the firmware.

When firmware receives this address, it will program each of the
Reply Descriptor Post Queue registers, as each reply queue has its
own register. Thus the firmware, starting from a base address it
determines the starting address of the subsequent reply queues
through some simple arithmetic calculations.

The size of this contiguous block of memory pool is directly proportional
to number of MSI-X vectors and the HBA queue depth. For example higher
MSIX vectors requires larger contiguous block of memory pool.

But some of the OS kernels are unable to allocate this larger
contiguous block of memory pool.

So, the proposal is to allocate memory independently for each
Reply Queue and pass down all of the addresses to the firmware.
Then the firmware will just take each address and program the value
into the correct register.

When HBAs with older firmware(i.e. without RDPQ capability) is used
with this new driver then the max_msix_vectors value would be set
to 8 by default.

Change set in v2:

1. Declared the _base_get_ioc_facts() functions at the beginning of the mpt3sas_base.c file
instead of moving all these functions before mpt3sas_base_map_resources() function
        a. _base_wait_for_doorbell_int()
        b. _base_wait_for_doorbell_ack()
        c. _base_wait_for_doorbell_not_used()
        d. _base_handshake_req_reply_wait()
        e. _base_get_ioc_facts()

2. Initially set the consistent DMA mask to 32 bit and then change it to 64 bit mask
after allocating RDPQ pools by calling the function _base_change_consistent_dma_mask.
This is to ensure that all the upper 32 bits of RDPQ entries's base address to be same.

3. Reduced the redundancy between the RDPQ and non-RDPQ support in these following functions
        a. _base_release_memory_pools()
        b. _base_allocate_memory_pools()
        c. _base_send_ioc_init()
        d. _base_make_ioc_operational()

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
---
 drivers/scsi/mpt3sas/mpt3sas_base.c | 231 +++++++++++++++++++++++++++---------
 drivers/scsi/mpt3sas/mpt3sas_base.h |  18 ++-
 2 files changed, 189 insertions(+), 60 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index d71f135..408eb81 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -92,6 +92,11 @@ MODULE_PARM_DESC(mpt3sas_fwfault_debug,
 	" enable detection of firmware fault and halt firmware - (default=0)");
 
 
+static int dma_mask;
+
+static int
+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag);
+
 /**
  * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
  *
@@ -1482,17 +1487,23 @@ static int
 _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
 {
 	struct sysinfo s;
-	char *desc = NULL;
+	u64 consistent_dma_mask;
+
+	if (dma_mask)
+		consistent_dma_mask = DMA_BIT_MASK(64);
+	else
+		consistent_dma_mask = DMA_BIT_MASK(32);
 
 	if (sizeof(dma_addr_t) > 4) {
 		const uint64_t required_mask =
 		    dma_get_required_mask(&pdev->dev);
 		if ((required_mask > DMA_BIT_MASK(32)) &&
 		    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
-		    !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+		    !pci_set_consistent_dma_mask(pdev,
+		      DMA_BIT_MASK(consistent_dma_mask))) {
 			ioc->base_add_sg_single = &_base_add_sg_single_64;
 			ioc->sge_size = sizeof(Mpi2SGESimple64_t);
-			desc = "64";
+			dma_mask = 64;
 			goto out;
 		}
 	}
@@ -1501,19 +1512,30 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
 	    && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
 		ioc->base_add_sg_single = &_base_add_sg_single_32;
 		ioc->sge_size = sizeof(Mpi2SGESimple32_t);
-		desc = "32";
+		dma_mask = 32;
 	} else
 		return -ENODEV;
 
  out:
 	si_meminfo(&s);
 	pr_info(MPT3SAS_FMT
-		"%s BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
-		ioc->name, desc, convert_to_kb(s.totalram));
+		"%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
+		ioc->name, dma_mask, convert_to_kb(s.totalram));
 
 	return 0;
 }
 
+static int
+_base_change_consistent_dma_mask(struct MPT3SAS_ADAPTER *ioc,
+				      struct pci_dev *pdev)
+{
+	if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+		if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+			return -ENODEV;
+	}
+	return 0;
+}
+
 /**
  * _base_check_enable_msix - checks MSIX capabable.
  * @ioc: per adapter object
@@ -1698,6 +1720,9 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
 	  ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count,
 	  ioc->cpu_count, max_msix_vectors);
 
+	if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+		max_msix_vectors = 8;
+
 	if (max_msix_vectors > 0) {
 		ioc->reply_queue_count = min_t(int, max_msix_vectors,
 			ioc->reply_queue_count);
@@ -1821,6 +1846,16 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
 	}
 
 	_base_mask_interrupts(ioc);
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out_fail;
+
+	if (!ioc->rdpq_array_enable_assigned) {
+		ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+		ioc->rdpq_array_enable_assigned = 1;
+	}
+
 	r = _base_enable_msix(ioc);
 	if (r)
 		goto out_fail;
@@ -2496,7 +2531,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
 static void
 _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
 {
-	int i;
+	int i = 0;
+	struct reply_post_struct *rps;
 
 	dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
 	    __func__));
@@ -2541,15 +2577,25 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
 		ioc->reply_free = NULL;
 	}
 
-	if (ioc->reply_post_free) {
-		pci_pool_free(ioc->reply_post_free_dma_pool,
-		    ioc->reply_post_free, ioc->reply_post_free_dma);
+	if (ioc->reply_post) {
+		do {
+			rps = &ioc->reply_post[i];
+			if (rps->reply_post_free) {
+				pci_pool_free(
+				    ioc->reply_post_free_dma_pool,
+				    rps->reply_post_free,
+				    rps->reply_post_free_dma);
+				dexitprintk(ioc, pr_info(MPT3SAS_FMT
+				    "reply_post_free_pool(0x%p): free\n",
+				    ioc->name, rps->reply_post_free));
+				rps->reply_post_free = NULL;
+			}
+		} while (ioc->rdpq_array_enable &&
+			   (++i < ioc->reply_queue_count));
+
 		if (ioc->reply_post_free_dma_pool)
 			pci_pool_destroy(ioc->reply_post_free_dma_pool);
-		dexitprintk(ioc, pr_info(MPT3SAS_FMT
-		    "reply_post_free_pool(0x%p): free\n", ioc->name,
-		    ioc->reply_post_free));
-		ioc->reply_post_free = NULL;
+		kfree(ioc->reply_post);
 	}
 
 	if (ioc->config_page) {
@@ -2696,6 +2742,65 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc,  int sleep_flag)
 	    ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
 	    ioc->chains_needed_per_io));
 
+	/* reply post queue, 16 byte align */
+	reply_post_free_sz = ioc->reply_post_queue_depth *
+	    sizeof(Mpi2DefaultReplyDescriptor_t);
+
+	sz = reply_post_free_sz;
+	if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
+		sz *= ioc->reply_queue_count;
+
+	ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
+	    (ioc->reply_queue_count):1,
+	    sizeof(struct reply_post_struct), GFP_KERNEL);
+
+	if (!ioc->reply_post) {
+		pr_err(MPT3SAS_FMT "reply_post_free pool: kcalloc failed\n",
+			ioc->name);
+		goto out;
+	}
+	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+	    ioc->pdev, sz, 16, 0);
+	if (!ioc->reply_post_free_dma_pool) {
+		pr_err(MPT3SAS_FMT
+		 "reply_post_free pool: pci_pool_create failed\n",
+		 ioc->name);
+		goto out;
+	}
+	i = 0;
+	do {
+		ioc->reply_post[i].reply_post_free =
+		    pci_pool_alloc(ioc->reply_post_free_dma_pool,
+		    GFP_KERNEL,
+		    &ioc->reply_post[i].reply_post_free_dma);
+		if (!ioc->reply_post[i].reply_post_free) {
+			pr_err(MPT3SAS_FMT
+			"reply_post_free pool: pci_pool_alloc failed\n",
+			ioc->name);
+			goto out;
+		}
+		memset(ioc->reply_post[i].reply_post_free, 0, sz);
+		dinitprintk(ioc, pr_info(MPT3SAS_FMT
+		    "reply post free pool (0x%p): depth(%d),"
+		    "element_size(%d), pool_size(%d kB)\n", ioc->name,
+		    ioc->reply_post[i].reply_post_free,
+		    ioc->reply_post_queue_depth, 8, sz/1024));
+		dinitprintk(ioc, pr_info(MPT3SAS_FMT
+		    "reply_post_free_dma = (0x%llx)\n", ioc->name,
+		    (unsigned long long)
+		    ioc->reply_post[i].reply_post_free_dma));
+		total_sz += sz;
+	} while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
+
+	if (dma_mask == 64) {
+		if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
+			pr_warn(MPT3SAS_FMT
+			    "no suitable consistent DMA mask for %s\n",
+			    ioc->name, pci_name(ioc->pdev));
+			goto out;
+		}
+	}
+
 	ioc->scsiio_depth = ioc->hba_queue_depth -
 	    ioc->hi_priority_depth - ioc->internal_depth;
 
@@ -2910,40 +3015,6 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc,  int sleep_flag)
 		ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
-		sz = reply_post_free_sz;
-	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-	    ioc->pdev, sz, 16, 0);
-	if (!ioc->reply_post_free_dma_pool) {
-		pr_err(MPT3SAS_FMT
-			"reply_post_free pool: pci_pool_create failed\n",
-			ioc->name);
-		goto out;
-	}
-	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-	    GFP_KERNEL, &ioc->reply_post_free_dma);
-	if (!ioc->reply_post_free) {
-		pr_err(MPT3SAS_FMT
-			"reply_post_free pool: pci_pool_alloc failed\n",
-			ioc->name);
-		goto out;
-	}
-	memset(ioc->reply_post_free, 0, sz);
-	dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply post free pool" \
-	    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-	    ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-	    sz/1024));
-	dinitprintk(ioc, pr_info(MPT3SAS_FMT
-		"reply_post_free_dma = (0x%llx)\n",
-		ioc->name, (unsigned long long)
-	    ioc->reply_post_free_dma));
-	total_sz += sz;
-
 	ioc->config_page_sz = 512;
 	ioc->config_page = pci_alloc_consistent(ioc->pdev,
 	    ioc->config_page_sz, &ioc->config_page_dma);
@@ -3626,6 +3697,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
 	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
 		ioc->ir_firmware = 1;
+	if ((facts->IOCCapabilities &
+	      MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
+		ioc->rdpq_array_capable = 1;
 	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
 	facts->IOCRequestFrameSize =
 	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -3662,9 +3736,12 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 {
 	Mpi2IOCInitRequest_t mpi_request;
 	Mpi2IOCInitReply_t mpi_reply;
-	int r;
+	int i, r = 0;
 	struct timeval current_time;
 	u16 ioc_status;
+	u32 reply_post_free_array_sz = 0;
+	Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+	dma_addr_t reply_post_free_array_dma;
 
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
 	    __func__));
@@ -3693,9 +3770,31 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 	    cpu_to_le64((u64)ioc->request_dma);
 	mpi_request.ReplyFreeQueueAddress =
 	    cpu_to_le64((u64)ioc->reply_free_dma);
-	mpi_request.ReplyDescriptorPostQueueAddress =
-	    cpu_to_le64((u64)ioc->reply_post_free_dma);
 
+	if (ioc->rdpq_array_enable) {
+		reply_post_free_array_sz = ioc->reply_queue_count *
+		    sizeof(Mpi2IOCInitRDPQArrayEntry);
+		reply_post_free_array = pci_alloc_consistent(ioc->pdev,
+			reply_post_free_array_sz, &reply_post_free_array_dma);
+		if (!reply_post_free_array) {
+			pr_err(MPT3SAS_FMT
+			"reply_post_free_array: pci_alloc_consistent failed\n",
+			ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+		memset(reply_post_free_array, 0, reply_post_free_array_sz);
+		for (i = 0; i < ioc->reply_queue_count; i++)
+			reply_post_free_array[i].RDPQBaseAddress =
+			    cpu_to_le64(
+				(u64)ioc->reply_post[i].reply_post_free_dma);
+		mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)reply_post_free_array_dma);
+	} else {
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
+	}
 
 	/* This time stamp specifies number of milliseconds
 	 * since epoch ~ midnight January 1, 1970.
@@ -3723,7 +3822,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 	if (r != 0) {
 		pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n",
 		    ioc->name, __func__, r);
-		return r;
+		goto out;
 	}
 
 	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3733,7 +3832,12 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 		r = -EIO;
 	}
 
-	return 0;
+out:
+	if (reply_post_free_array)
+		pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
+				    reply_post_free_array,
+				    reply_post_free_array_dma);
+	return r;
 }
 
 /**
@@ -4283,7 +4387,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 	struct _tr_list *delayed_tr, *delayed_tr_next;
 	struct adapter_reply_queue *reply_q;
 	long reply_post_free;
-	u32 reply_post_free_sz;
+	u32 reply_post_free_sz, index = 0;
 
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
 	    __func__));
@@ -4354,9 +4458,9 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 		_base_assign_reply_queues(ioc);
 
 	/* initialize Reply Post Free Queue */
-	reply_post_free = (long)ioc->reply_post_free;
 	reply_post_free_sz = ioc->reply_post_queue_depth *
 	    sizeof(Mpi2DefaultReplyDescriptor_t);
+	reply_post_free = (long)ioc->reply_post[index].reply_post_free;
 	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
 		reply_q->reply_post_host_index = 0;
 		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
@@ -4366,7 +4470,15 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
 			    cpu_to_le64(ULLONG_MAX);
 		if (!_base_is_controller_msix_enabled(ioc))
 			goto skip_init_reply_post_free_queue;
-		reply_post_free += reply_post_free_sz;
+		/*
+		 * If RDPQ is enabled, switch to the next allocation.
+		 * Otherwise advance within the contiguous region.
+		 */
+		if (ioc->rdpq_array_enable)
+			reply_post_free = (long)
+			    ioc->reply_post[++index].reply_post_free;
+		else
+			reply_post_free += reply_post_free_sz;
 	}
  skip_init_reply_post_free_queue:
 
@@ -4477,6 +4589,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
 		goto out_free_resources;
 	}
 
+	ioc->rdpq_array_enable_assigned = 0;
 	r = mpt3sas_base_map_resources(ioc);
 	if (r)
 		goto out_free_resources;
@@ -4853,6 +4966,12 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag,
 	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
 	if (r)
 		goto out;
+
+	if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+		panic("%s: Issue occurred with flashing controller firmware."
+		      "Please reboot the system and ensure that the correct"
+		      " firmware version is running\n", ioc->name);
+
 	r = _base_make_ioc_operational(ioc, sleep_flag);
 	if (!r)
 		_base_reset_handler(ioc, MPT3_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index e920728..d0eb624 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -569,6 +569,11 @@ struct mpt3sas_port_facts {
 	u16			MaxPostedCmdBuffers;
 };
 
+struct reply_post_struct {
+	Mpi2ReplyDescriptorsUnion_t	*reply_post_free;
+	dma_addr_t			reply_post_free_dma;
+};
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
@@ -712,8 +717,11 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *				is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -914,8 +922,10 @@ struct MPT3SAS_ADAPTER {
 
 	/* reply post queue */
 	u16		reply_post_queue_depth;
-	Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-	dma_addr_t	reply_post_free_dma;
+	struct reply_post_struct *reply_post;
+	u8		rdpq_array_capable;
+	u8		rdpq_array_enable;
+	u8		rdpq_array_enable_assigned;
 	struct dma_pool *reply_post_free_dma_pool;
 	u8		reply_queue_count;
 	struct list_head reply_queue_list;
-- 
2.0.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-08-12  9:34 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-25 10:41 [RESEND][PATCH 7/8][SCSI]mpt3sas: Added Reply Descriptor Post Queue (RDPQ) Array support Reddy, Sreekanth
2014-08-05 15:24 ` Tomas Henzl
     [not found]   ` <CAK=zhgqBfFpUJ1FTQGNKoGnLBBsX=6AGwr14DZVNjdAjihY0sw@mail.gmail.com>
2014-08-06 15:56     ` Tomas Henzl
2014-08-12  9:34 Sreekanth Reddy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).